首页 > 代码库 > Socket编程实践(4)
Socket编程实践(4)
Socket API 中的地址复用
服务器端尽可能使用SO_REUSEADDR,在绑定之前尽可能调用setsockopt来设置SO_REUSEADDR套接字选项。该选项可以使得不必等待TIME_WAIT状态消失就可以重启服务器.
SYNOPSIS #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
可以在bind之前添加代码(完整代码请参照博文最后):
int optval = 1; if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -1) { err_exit("setsockopt SO_REUSEADDR error"); }
用以支持地址复用.
Socket服务多并发--多客户端连接
可以从上图看出,我们的服务器最大的缺点就是无法支持多客户连接,即使客户端能够连接到服务器上,服务器也不为该客户做服务,(直接没什么反应),虽然链接是有的(也就是说,客户端是已经连接到服务器上的了,但是服务器就是不搭理你....)
从服务器的下面这段代码我们可以看出端倪....
struct sockaddr_in peerAddr; socklen_t peerLen; //注意:一次只能处理一个连接 int peerSockfd = accept(sockfd, (struct sockaddr *)&peerAddr,&peerLen); if (peerSockfd == -1) { err_exit("accept error"); } //打印客户信息 cout << "Client:" << endl; cout << "\tsin_port: " << ntohs(peerAddr.sin_port) << endl; cout << "\tsin_addr: " << inet_ntoa(peerAddr.sin_addr) << endl; cout << "\tsocket: " << peerSockfd << endl; //.....
即服务器运行一次,只能为一个客户端服务一次!!!!
并发服务器实现
1.客户端向服务器发送请求
2.典型的(多进程)并发服务器程序框架
//完整的server端代码 #include "commen.h" int main() { int sockfd = socket(AF_INET,SOCK_STREAM,0); if (sockfd == -1) { err_exit("socket error"); } int optval = 1; if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -1) { err_exit("setsockopt SO_REUSEADDR error"); } struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8002); serverAddr.sin_addr.s_addr = INADDR_ANY; //绑定本机的任意一个IP地址 //serverAddr.sin_addr.s_addr = inet_addr("10.255.218.20"); if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == -1) { err_exit("bind error"); } //一旦调用了listen,则sockfd编程被动套接字:等待客户端的连接(只能接受连接,不能发送连接) if (listen(sockfd,SOMAXCONN) == -1) { err_exit("listen error"); } struct sockaddr_in peerAddr; socklen_t peerLen; while (true) { int peerSockfd = accept(sockfd, (struct sockaddr *)&peerAddr,&peerLen); if (peerSockfd == -1) { err_exit("accept error"); } //打印客户信息 cout << "Client:" << endl; cout << "\tsin_port: " << ntohs(peerAddr.sin_port) << endl; cout << "\tsin_addr: " << inet_ntoa(peerAddr.sin_addr) << endl; cout << "\tsocket: " << peerSockfd << endl; //每有一个客户端连接进来,就fork一个子进程, //相应的业务处理由子进程完成,父进程继续监听 pid_t pid = fork(); if (pid == -1) { close(sockfd); close(peerSockfd); err_exit("fork error"); } else if (pid == 0) //子进程,处理业务 { close(sockfd); //子进程关闭监听套接字,因为子进程不负责监听任务 char buf[BUFSIZ]; memset(buf,0,sizeof(buf)); ssize_t readCount = 0; while ((readCount = read(peerSockfd,buf,sizeof(buf))) >= 0) { //如果在读取数据的过程中,read返回0,则说明对方已经关闭连接 if (readCount == 0) { err_exit("read peerSockfd error"); } if (write(peerSockfd,buf,readCount) == -1) { err_exit("write peerSockfd error"); } buf[readCount] = ‘\0‘; fputs(buf,stdout); memset(buf,0,sizeof(buf)); } } else if (pid > 0) //父进程 { close(peerSockfd); //父进程关闭连接套接字,因为父进程不负责为子进程服务 } } close(sockfd); return 0; }
Socket编程实践(4)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。