socket编程(3-1)
本章目标
- REUSEADDR
- 处理多客户连接(process-per-connection)
- 点对点聊天程序实现
1.回顾
服务器端通过套接字conn,客户端通过套接字sock,他们可以互相通信
可想而知,这两个套接字都有自己的地址。
对于服务器来说,它的套接字地址是在绑定的时候确定的,
对于客户端来说,它的套接字是在连接成功后确定的。端口号是自动获取的。
注意:connect函数的第三个参数一定要初始化。不然会连接失败。
服务器和客户端通过两个套接字实现虚连接,是一种逻辑连接

构成一个连接 四要素 : 服务器IP port 客户端IP port
2.缺陷
服务器重启后,不能立即使用
出现错误提示: bind:address already in use
这里的主要原因在于:服务器重启后,又要去绑定地址,这时候的地址是不能绑定成功的。因为此时
网络处于一个状态 netstat -an|grep TIME_WAIT
renzhuang@geroge:~/netcoding/08socket$ netstat -an |grep TIME_WAIT
tcp 0 0 127.0.0.1:5188 127.0.0.1:56457 TIME_WAIT
服务器端处于TIME_WAIT状态
解决:用REUSEADDR来解决
并不意味着服务器启动后,还可以启动一个服务器!!!明显地址已经被使用了。。
服务器端代码:
#include<stdio.h> #include <sys/socket.h> #include<sys/types.h> #include<unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include<stdlib.h> #include<errno.h> #include<string.h> int main() { /*create a socket*/ int sockfd; if((sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0) printf("socket err"); /*init addr*/ struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/ /*inet_aton("127.0.0.1",&servaddr.sin_addr);*/ int on = 1;/*开启地址重复利用*/ if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) printf("setsockopt err"); /*将创建的套接字与本地地址进行绑定*/ if(bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0) printf("blind err"); /*监听套接字*/ if (listen(sockfd,SOMAXCONN) < 0 ) printf("listen err:"); struct sockaddr_in peeraddr; socklen_t peerlen = sizeof(peeraddr); int conn; /*主动套接字*/ if ((conn = accept(sockfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0 ) printf("accept err"); printf("ip = %s,port = %d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port)); /*处理通信的细节*/ char recvbuf[1024]; while(1) { memset(recvbuf,0,sizeof(recvbuf)); int ret = read(conn,recvbuf,sizeof(recvbuf)); fputs(recvbuf,stdout); write(conn,recvbuf,ret); } close(conn); close(sockfd); return 0; }
客户端代码没有更改:
#include<stdio.h> #include <sys/socket.h> #include<sys/types.h> #include<unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include<stdlib.h> #include<errno.h> #include<string.h> int main() { /*创建套接字*/ int sockfd; if((sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0) printf("socket err"); /*serv addr and port*/ struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); /*连接,一旦连接成功,sockfd套接字就处于已连接状态,从逻辑上 是与服务器端的conn套接字连接*/ if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) <0) printf("connect err"); char sendbuf[1024]={0}; char recvbuf[1024]={0}; while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL) { write(sockfd,sendbuf,strlen(sendbuf)); read(sockfd,recvbuf,sizeof(recvbuf)); fputs(recvbuf,stdout); memset(sendbuf,0,sizeof(sendbuf)); memset(recvbuf,0,sizeof(recvbuf)); } close(sockfd); return 0; }
现在服务器重启后可以立即使用,不会处于TIME_WAIT状态。
但是,现在服务器只能处理单个客户端连接。下一节,我们将处理多个客户的连接情况(并发)

浙公网安备 33010602011771号