转自:http://blog.csdn.net/youjun9007228198/article/details/19946129linux
经过 fork 建立子进程的方式能够实现,其余状况下不行。
当链接到来时,子进程、父进程均可以 accept, 这就是著名的“惊群”问题(thundering herd problem)。服务器
惊群现象多线程
在该模型下(多个子进程同时共享监听套接字)便可实现服务器并发处理客户端的链接。这里要注意的是,计算机三次握手建立链接是不须要服务进程参数的,而服务进程仅仅要作的事调用accept将已创建的链接构建对应的链接套接字connfd(可参考 http://blog.csdn.net/ordeder/article/details/21551567)。多个服务进程同时阻塞在accept等待监听套接字已创建链接的信息,那么当内核在该监听套接字上创建一个链接,那么将同时唤起这些处于accept阻塞的服务进程,从而致使“惊群现象”的产生,唤起多余的进程间影响服务器的性能(仅有一个服务进程accept成功,其余进程被唤起后没抢到“链接”而再次进入休眠)。并发
一直疑惑一个应用app如何才能以多进程,多线程的方式运行。对于多线程可能很好理解,咱们只要在进程中启用多线程的模式便可。也就是来一个请求,咱们就用函数pthread_create()启用一个线程便可。这样咱们的应用就能够在单进程,多线程的模式下工做。app
但咱们知道一个应用app一般工做在多进程,多线程的模式下,它的效率是最高的。那么咱们如何才能作到多进程模式呢?经验告诉咱们,若是屡次启动一个进程会报错:“Address already in use!"。这是因为bind函数致使的,因为该端口号已经被监听了。socket
其实咱们只要在绑定端口号(bind函数)以后,监听端口号以前(listen函数),用fork()函数生成子进程,这样子进程就能够克隆父进程,达到监听同一个端口的目的。好了,废话很少说,咱们看一下具体代码。函数
server.coop
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<unistd.h> #define oops(m) {perror(m); exit(1);} int main(){ int sock_id; struct sockaddr_in saddr; sock_id = socket(PF_INET, SOCK_STREAM, 0); saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); saddr.sin_port = htons(9988); saddr.sin_family = AF_INET; int ret = bind(sock_id, (struct sockaddr *) &saddr, sizeof(saddr));//绑定IP地址和端口 if(ret == -1) oops("bind error");//若是返回-1,则绑定失败,通常为“Address alreay in use” int i; for(i = 0; i < 6; i++){//连续建立六个子进程 int pid = fork(); if(pid == 0) break; } listen(sock_id, 1); while(1){ int sock = accept(sock_id, NULL, 0); char buf[128]; int readnum; readnum = read(sock, buf, 127); buf[readnum] = '\0'; printf("pid=%d, mesg: %s\n", getpid(), buf); fflush(stdout); close(sock); } return 1; }
client.c性能
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<netinet/in.h> int main(){ int i=0; struct sockaddr_in saddr; saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); saddr.sin_port = htons(9988); saddr.sin_family = AF_INET; int addlen = sizeof(saddr); for(; i < 30; i++){ int sock=socket(AF_INET, SOCK_STREAM, 0); connect(sock, (struct sockaddr *) &saddr, addlen); write(sock, "Hello Server!", 13); } }
运行结果:spa