socket服务器并发处理
我们知道,服务器通常是要同时服务多个客户端的,如果我们运行上一篇实现的server和client之后,再开一个终端运行client试试,新的client就不能能得到服务了。因为服务器之支持一个连接。
网络服务器通常用fork来同时服务多个客户端,父进程专门负责监听端口,每次accept一个新的客户端连接就fork出一个子进程专门服务这个客户端。但是子进程退出时会产生僵尸进程,父进程要注意处理SIGCHLD信号和调用wait清理僵尸进程。
下面是代码框架:
- listenfd = socket(...);
- bind(listenfd, ...);
- listen(listenfd, ...);
- while (1) {
- connfd= accept(listenfd, ...);
- n= fork();
- if(n == -1) {
- perror("callto fork");
- exit(1);
- }else if (n == 0) {
- close(listenfd);
- while(1) {
- read(connfd,...);
- ...
- write(connfd,...);
- }
- close(connfd);
- exit(0);
- }else
- close(connfd);
- }
现在做一个测试,首先启动server,然后启动client,然后用Ctrl-C使server终止,这时马上再运行server,结果是:
binderror: Address already in use
这是因为,虽然server的应用程序终止了,但TCP协议层的连接并没有完全断开,因此不能再次监听同样的server端口。server终止时,socket描述符会自动关闭并发FIN段给client,client收到FIN后处于CLOSE_WAIT状态,但是client并没有终止,也没有关闭socket描述符,因此不会发FIN给server,因此server的TCP连接处于FIN_WAIT2状态。
现在用Ctrl-C把client也终止掉,再观察现象结果是:
binderror: Address already in useclient
终止时自动关闭socket描述符,server的TCP连接收到client发的FIN段后处于TIME_WAIT状态。TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态,因为我们先Ctrl-C终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口。MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在Linux上一般经过半分钟后就可以再次启动server了。
在server的TCP连接没有完全断开之前不允许重新监听是不合理的,因为,TCP连接没有完全断开指的是connfd(127.0.0.1:8000)没有完全断开,而我们重新监听的是listenfd(0.0.0.0:8000),虽然是占用同一个端口,但IP地址不同,connfd对应的是与某个客户端通讯的一个具体的IP地址,而listenfd对应的是wildcard address。解决这个问题的方法是使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP地址不同的多个socket描述符。在server代码的socket()和bind()调用之间插入如下代码:
- int opt = 1;
- setsockopt(listenfd, SOL_SOCKET,SO_REUSEADDR, &opt, sizeof(opt));
select是网络程序中很常用的一个系统调用,它可以同时监听多个阻塞的文件描述符(例如多个网络连接),哪个有数据到达就处理哪个,这样,不需要fork和多进程就可以实现并发服务的server。
- /* server.c */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <netinet/in.h>
- #include "wrap.h"
- #define MAXLINE 80
- #define SERV_PORT 8000
- int main(int argc, char **argv)
- {
- inti, maxi, maxfd, listenfd, connfd, sockfd;
- intnready, client[FD_SETSIZE];
- ssize_tn;
- fd_setrset, allset;
- charbuf[MAXLINE];
- charstr[INET_ADDRSTRLEN];
- socklen_tcliaddr_len;
- structsockaddr_in cliaddr, servaddr;
- listenfd= Socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr,sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr= htonl(INADDR_ANY);
- servaddr.sin_port = htons(SERV_PORT);
- Bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
- Listen(listenfd,20);
- maxfd= listenfd; /* initialize */
- maxi= -1; /* indexinto client[] array */
- for(i = 0; i < FD_SETSIZE; i++)
- client[i] = -1; /* -1 indicates available entry */
- FD_ZERO(&allset);
- FD_SET(listenfd,&allset);
- for( ; ; ) {
- rset= allset; /* structure assignment */
- nready= select(maxfd+1, &rset, NULL, NULL, NULL);
- if(nready < 0)
- perr_exit("selecterror");
- if(FD_ISSET(listenfd, &rset)) { /* new client connection */
- cliaddr_len= sizeof(cliaddr);
- connfd= Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
- printf("receivedfrom %s at PORT %d\n",
- inet_ntop(AF_INET, &cliaddr.sin_addr,str, sizeof(str)),
- ntohs(cliaddr.sin_port));
- for(i = 0; i < FD_SETSIZE; i++)
- if(client[i] < 0) {
- client[i]= connfd; /* save descriptor */
- break;
- }
- if(i == FD_SETSIZE) {
- fputs("toomany clients\n", stderr);
- exit(1);
- }
- FD_SET(connfd,&allset); /* add newdescriptor to set */
- if(connfd > maxfd)
- maxfd= connfd; /* for select */
- if(i > maxi)
- maxi= i; /* max index in client[] array */
- if(--nready == 0)
- continue; /* no more readable descriptors */
- }
- for(i = 0; i <= maxi; i++) { /* check allclients for data */
- if( (sockfd = client[i]) < 0)
- continue;
- if(FD_ISSET(sockfd, &rset)) {
- if( (n = Read(sockfd, buf, MAXLINE)) == 0) {
- /*connection closed by client */
- Close(sockfd);
- FD_CLR(sockfd,&allset);
- client[i]= -1;
- }else {
- intj;
- for(j = 0; j < n; j++)
- buf[j]= toupper(buf[j]);
- Write(sockfd,buf, n);
- }
- if(--nready == 0)
- break; /* no more readable descriptors */
- }
- }
- }
- }
socket服务器并发处理的更多相关文章
- Socket服务器整体架构概述
转载:http://www.cnblogs.com/tianzhiliang/archive/2010/10/28/1863684.html Socket服务器主要用于提供高效.稳定的数据处理.消息转 ...
- 转:Socket服务器整体架构概述
Socket服务器主要用于提供高效.稳定的数据处理.消息转发等服务,它直接决定了前台应用程序的性能.我们先从整体上认识一下Socket服务器,Socket服务器从架构上一般分为:网络层.业务逻辑层.会 ...
- 通过监控线程状态来保证socket服务器的稳定运行
云平台中使用的socket服务器是我们自己定义一套通信协议,并通过C#实现的一个socket服务. 该服务目前是和web服务一起运行在IIS容器中,通过启动一个永不退出的新线程来监听端口. 在开发的初 ...
- Java NIO 非阻塞Socket服务器构建
推荐阅读IBM developerWorks中NIO的入门教程,尤其是对块I/O和流I/O不太清楚的开发者. 说到socket服务器,第一反应是java.net.Socket这个类.事实上在并发和响应 ...
- socket服务器开发中的SO_REUSEADDR选项与让人心烦的TIME_WAIT
1 发现问题 我在开发一个socket服务器程序并反复调试的时候,发现了一个让人无比心烦的情况:每次kill掉该服务器进程并重新启动的时候,都会出现bind错误:error:98,Address al ...
- workerman是一个高性能的PHP socket服务器框架
workerman-chatorkerman是一款纯PHP开发的开源高性能的PHP socket服务器框架.被广泛的用于手机app.手游服务端.网络游戏服务器.聊天室服务器.硬件通讯服务器.智能家居. ...
- java的nio之:java的bio流下实现的socket服务器同步阻塞模型和socket的伪异步的socket服务器的通信模型
同步I/O模型的弊端===>每一个线程的创建都会消耗服务端内存,当大量请求进来,会耗尽内存,导致服务宕机 伪异步I/O的弊端分析===>当对Socket的输入流进行读取操作的时候,它会一直 ...
- 以C#编写的Socket服务器的Android手机聊天室Demo
内容摘要 1.程序架构 2.通信协议 3.服务器源代码 4.客户端源代码 5.运行效果 一.程序架构 在开发一个聊天室程序时,我们可以使用Socket.Remoting.WCF这些具有双向通信的协议或 ...
- 再次回首 TCP Socket服务器编程
转载:http://www.cnblogs.com/zc22/archive/2010/06/27/1766007.html ------------------ 前言 --------------- ...
随机推荐
- makefile 与android.mk中加信息打印
makefile里面加打印: [table]@echo ' zImage - Compressed kernel image' android.mk里面加信息打印: $(warning TEXT... ...
- jsp中获取spring 管理的bean(通过config)
WebApplicationContext wac = (WebApplicationContext)config.getServletContext().getAttribute(WebApplic ...
- Cocos2d-x 避免手工输入项目需要编译的cpp文件到Android.mk里
手工输入项目需要编译的cpp文件到Android.mk里的缺点 1)繁琐,如果cpp文件很多,简直无法忍受 2)手工输入过程中容易出现错误 3)如果cpp文件更改名称,需要修改Android.mk文件 ...
- Google的分布式计算模型Map Reduce map函数将输入分割成key/value对
http://www.nowamagic.net/librarys/veda/detail/1768 上一篇 大规模分布式数据处理平台Hadoop的介绍 中提到了Google的分布式计算模型Map R ...
- [Android5 系列—] 1. 构建一个简单的用户界面
前言 安卓应用的用户界面是构建在View 和ViewGroup 这两个物件的层级之上的. View 就是一般的UI组件.像button,输入框等. viewGroup 是一些不可见的view的容器,用 ...
- opencv中的SVM图像分类(二)
opencv中的SVM图像分类(二) 标签: svm图像 2015-07-30 08:45 8296人阅读 评论(35) 收藏 举报 分类: [opencv应用](5) 版权声明:本文为博主原创文 ...
- 在“云基础设施即服务的魔力象限”报告中,AWS 连续三年被评为领导者
在"2014 云基础设施即服务的魔力象限"中.Gartner 将 Amazon Web Services 定位在"领导者象限"中,并评价 AWS 拥有最完整.最 ...
- UML类图组成
本文转载至 http://blog.csdn.net/fengsh998/article/details/8105666 UML类图的相关知识,UML类图(Classdiagram)是最常用的 ...
- 基于EasyDarwin实现幼儿园监控类项目
移动互联网越来越普及,幼儿园监控类的项目也越来越多,如何能够以最低的成本.最快的速度搭建一套幼儿园监控类的平台成了许多开发者的需求,那么我们今天就来简单探讨一下如何基于EasyDarwin实现一套幼儿 ...
- easyui Combotree 怎么加载数据 支持多选
1.开发环境vs2012 mvc4 c# 2.HTML前端代码 <%@ Page Language="C#" AutoEventWireup="true" ...