1
/*
socket->bind->listen->accept->recv/recvfrom->send/sendto->close
2
3
客户端:socket->connect->send/sendto->recv/recvfrom->close
4
5
其中服务器端首先建立起socket,然后调用本地端口的绑定,接着就开始与客服端建立联系,并接收客户端发送的消息。
6
客户端则在建立socket之后调用connect函数来建立连接。
7
8
服务器端的源代码如下所示:
*/
9
10
/*
"server.c"
*/
11
12
#include<sys/types.h>
13
#include<sys/socket.h>
14
#include<stdio.h>
15
#include<stdlib.h>
16
#include<errno.h>
17
#include<
string
.h>
18
#include<unistd.h>
19
#include<netinet/
in
.h>
20
21
#define
PORT 3490
//
端口
22
23
#define
BUFFER_SIZE 1024
//
缓冲区大小
24
25
#define
MAX_QUE_CONN_NM 5
//
服务器等待连接队列的最大长度。
26
27
int
main(){
28
29
struct
sockaddr_in server_sockaddr,client_sockaddr;
//
分别定义服务器和客户端套接字
30
int
sin_size,recvbytes;
31
int
server_fd,client_fd;
32
char
buf[BUFFER_SIZE];
//
缓冲区
33
34
/*
35
SOCKET PASCAL FAR socket( int af, int type, int protocol);
36
af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。
37
type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。
38
常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
39
protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。
40
常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,
41
它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
42
*/
43
if
((server_fd = socket(AF_INET,SOCK_STREAM,
0
))== -
1
){
//
建立socket连接www.linuxidc.com
44
perror(
"
create socket fail
"
);
45
exit(
1
);
46
}
47
48
printf(
"
Socket id=%d\n
"
,server_fd);
49
50
/*
设置sockaddr_in结构体中的相关参数
*/
51
52
server_sockaddr.sin_family =
AF_INET;
53
server_sockaddr.sin_port = htons(PORT);
//
由于在写网络程序时字节的网络顺序和主机顺序会有问题
54
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
//
即0.0.0.0 任意地址
55
bzero(&(server_sockaddr.sin_zero),
8
);
56
int
i =
1
;
//
允许重复使用本地地址与套接字进行绑定
57
58
/*
int PASCAL FAR setsockopt(SOCKET s,int level,int optname,const char FAR *optval,int optlen);
59
s:标识一个套接字的描述符。
60
level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。
61
optname:需设置的选项。
62
optval:指针,指向存放选项值的缓冲区。
63
optlen:optval缓冲区长度。
64
*/
65
setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&i,
sizeof
(i));
66
67
/*
68
int bind(SOCKET socket, const struct sockaddr *address,
69
socklen_t address_len);
70
参数说明:
71
socket:是一个套接字。
72
address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。
73
address_len:确定address缓冲区的长度。
74
返回值:如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
75
*/
76
if
(bind(server_fd,(
struct
sockaddr *)&server_sockaddr,
sizeof
(
struct
sockaddr)) == -
1
){
//
绑定函数bind
77
perror(
"
bind fail
"
);
78
exit(
1
);
79
}
80
81
printf(
"
Bind success!\n
"
);
82
83
/*
84
int PASCAL FAR listen( SOCKET s, int backlog);
85
S:用于标识一个已捆绑未连接套接口的描述字。
86
backlog:等待连接队列的最大长度。
87
*/
88
if
(listen(server_fd,MAX_QUE_CONN_NM)== -
1
){
//
调用listen函数,创建为处理请求的队列
89
perror(
"
listen fail
"
);
90
exit(
1
);
91
}
92
93
printf(
"
Listening......\n
"
);
94
95
/*
96
SOCKET PASCAL FAR accept( SOCKET s, struct sockaddr FAR* addr,int FAR* addrlen);
97
s:套接口描述字,该套接口在listen()后监听连接。
98
addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。
99
addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。
100
*/
101
if
((client_fd = accept(server_fd,(
struct
sockaddr *)&client_sockaddr,&sin_size))==-
1
){
//
调用accept函数,等待客户端的接
102
perror(
"
accept fail
"
);
103
exit(
1
);
104
}
105
106
printf(
"
server: got connection from %s \n
"
,inet_ntoa(client_sockaddr.sin_addr));
107
108
memset(buf,
0
,
sizeof
(buf));
109
/*
110
int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags);
111
s:一个标识已连接套接口的描述字。
112
buf:用于接收数据的缓冲区。
113
len:缓冲区长度。
114
flags:指定调用方式。通常写成0
115
*/
116
if
((recvbytes = recv(client_fd,buf,BUFFER_SIZE,
0
)) == -
1
){
//
调用recv函数接收客户端的请求
117
perror(
"
recv fail
"
);
118
exit(
1
);
119
}
120
121
printf(
"
Received a message: %s\n
"
,buf);
122
123
124
/*
向客户起写数据
*/
125
if
(write(client_fd,
"
客户端我收到你发来的数据了,你能收到这句应答吗?\n
"
,
1024
)==-
1
)
126
perror(
"
write error!
"
);
127
128
close(client_fd);
129
130
close(server_fd);
131
exit(
0
);
132
}
133
134
135
136
137
138
/*
客户端
*/
139
/*
client.c 运行方式:./client localhost
*/
140
#include <stdio.h>
141
#include <stdlib.h>
142
#include <errno.h>
143
#include <
string
.h>
144
#include <netdb.h>
145
#include <sys/types.h>
146
#include <netinet/
in
.h>
147
#include <sys/socket.h>
148
#define
PORT 3490
149
#define
MAXDATASIZE 5000
150
int
main(
int
argc,
char
**
argv)
151
{
152
int
sockfd,nbytes;
153
char
buf[
1024
];
154
struct
hostent *
he;
155
struct
sockaddr_in srvaddr;
156
if
(argc!=
2
)
157
{
158
perror(
"
Usage:client hostname\n
"
);
159
exit(
1
);
160
}
161
/*
函数gethostbyname获得指定域名地址所对应的ip地址
*/
162
if
((he=gethostbyname(argv[
1
]))==
NULL)
163
{
164
perror(
"
gethostbyname
"
);
165
exit(
1
);
166
}
167
/*
创建套接字,返回套接字描述符
*/
168
if
((sockfd=socket(AF_INET,SOCK_STREAM,
0
))==-
1
)
169
{
170
perror(
"
create socket error
"
);
171
exit(
1
);
172
}
173
bzero(&srvaddr,
sizeof
(srvaddr));
174
/*
用获得的远程服务器进程的ip地址和端口号来填充一个internet套接字地址结构
*/
175
srvaddr.sin_family=
AF_INET;
176
srvaddr.sin_port=
htons(PORT);
177
srvaddr.sin_addr=*((
struct
in_addr *)he->
h_addr);
178
/*
用connect于这个远程服务器建立一个internet连接
*/
179
if
(connect(sockfd,(
struct
sockaddr *)&srvaddr,
sizeof
(
struct
sockaddr))==-
1
)
180
{
181
perror(
"
connect error
"
);
182
exit(
1
);
183
}
184
185
186
if
((send(sockfd,
"
客户端向服务端发送数据,服务端你收到了吗?
"
,
1024
,
0
)) == -
1
)
187
{
188
perror(
"
send error
"
);
189
exit(
1
);
190
}
191
192
193
194
/*
调用read函数读取服务器write过来的信息
*/
195
if
((nbytes=read(sockfd,buf,MAXDATASIZE))==-
1
)
196
{
197
perror(
"
read error
"
);
198
exit(
1
);
199
}
200
buf[nbytes]=
'
\0
'
;
201
printf(
"
read: %s
"
,buf);
202
close(sockfd);
203
}
运行方式: gcc -o service service.c
gcc -o client client.c
chmod +x service
chmod +x client
在一个终端运行:./service
在另一个终端运行:./client localhost
服务端输出:
Socket id=3 Bind success! Listening...... server: got connection from 127.0.0.1 Received a message: 客户端向服务端发送数据,服务端你收到了吗?
客户端输出:
read: 客户端我收到你发来的数据了,你能收到这句应答吗?

