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 }
View Code
运行方式: 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: 客户端我收到你发来的数据了,你能收到这句应答吗?