1.Socket地址复用

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);

服务端尽可能使用SO_REUSEADDR,在绑定之前尽可能调用setsockopt来设置SO_REUSEADDR套接字选项。该选项可以使得server不必等待TIME_WAIT状态消失就可以重启服务器(对于TIME_WAIT状态会在后面续有叙述).

可以在bind之前添加代码(完整代码请参照博文最后):

    int on = 1;if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1)err_exit("setsockopt SO_REUSEADDR error");

用以支持地址复用.

2.process-per-connecton

我们的echo服务器最大的缺点就是无法支持多客户连接,即使客户端能够连接到服务器上(client端connect时并没有出错返回), 服务器也不为该客户做服务,(直接没什么反应),虽然链接是有的(也就是说,客户端是已经连接到服务器上的了,但是服务器就是不搭理你....), 我们提出的改进方案是process-per-connection(一条连接一个进程, 我们在多线程那一章中曾经提出过一条连接一个线程, 这种方案相比较而言能够比多进程拥有更高的并发量);

/** 示例:echo server改进, 多进程模型(client并未更改)**/
void echo(int clientfd);
int main()
{int listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == -1)err_exit("socket error");int on = 1;if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1)err_exit("setsockopt SO_REUSEADDR error");struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8001);addr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)err_exit("bind error");if (listen(listenfd, SOMAXCONN) == -1)err_exit("listen error");struct sockaddr_in clientAddr;//谨记: 此处一定要初始化socklen_t addrLen = sizeof(clientAddr);while (true){int clientfd = accept(listenfd, (struct sockaddr *)&clientAddr, &addrLen);if (clientfd == -1)err_exit("accept error");//打印客户IP地址与端口号cout << "Client information: " << inet_ntoa(clientAddr.sin_addr)<< ", " << ntohs(clientAddr.sin_port) << endl;pid_t pid = fork();if (pid == -1)err_exit("fork error");else if (pid > 0)close(clientfd);//子进程处理链接else if (pid == 0){close(listenfd);echo(clientfd);//子进程一定要exit, 否则的话, 该子进程也会回到accept处exit(EXIT_SUCCESS);}}close(listenfd);
}
void echo(int clientfd)
{char buf[512] = {0};int readBytes;while ((readBytes = read(clientfd, buf, sizeof(buf))) > 0){cout << buf;if (write(clientfd, buf, readBytes) == -1)err_exit("write socket error");memset(buf, 0, sizeof(buf));}if (readBytes == 0){cerr << "client connect closed..." << endl;close(clientfd);}else if (readBytes == -1)err_exit("read socket error");
}

完整代码实现:

http://download.csdn.net/detail/hanqing280441589/8458053

3. P2P聊天程序设计与实现

server端与client都有两个进程:

(1)父进程负责从socket中读取数据将其写至终端, 由于父进程使用的是read系统调用的阻塞版本, 因此如果socket中没有数据的话, 父进程会一直阻塞; 如果read返回0, 表示对端连接关闭, 则父进程会发送SIGUSR1信号给子进程, 通知其退出;

(2)子进程负责从键盘读取数据将其写入socket, 如果键盘没有数据的话, 则fgets调用会一直阻塞;

//serever端代码与说明
int main()
{int listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == -1)err_exit("socket error");int on = 1;if (setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1)err_exit("setsockopt SO_REUSEADDR error");struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8001);addr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)err_exit("bind error");if (listen(listenfd, SOMAXCONN) == -1)err_exit("listen error");struct sockaddr_in clientAddr;socklen_t addrLen = sizeof(clientAddr);int clientfd = accept(listenfd, (struct sockaddr *)&clientAddr, &addrLen);if (clientfd == -1)err_exit("accept error");close(listenfd);//打印客户IP地址与端口号cout << "Client information: " << inet_ntoa(clientAddr.sin_addr)<< ", " << ntohs(clientAddr.sin_port) << endl;char buf[512] = {0};pid_t pid = fork();if (pid == -1)err_exit("fork error");//父进程: socket -> terminalelse if (pid > 0){int readBytes;while ((readBytes = read(clientfd, buf, sizeof(buf))) > 0){cout << buf;memset(buf, 0, sizeof(buf));}if (readBytes == 0)cout << "client connect closed...\nserver exiting..." << endl;else if (readBytes == -1)err_exit("read socket error");//通知子进程退出kill(pid, SIGUSR1);}//子进程: keyboard -> socketelse if (pid == 0){signal(SIGUSR1, sigHandler);while (fgets(buf, sizeof(buf), stdin) != NULL){if (write(clientfd, buf, strlen(buf)) == -1)err_exit("write socket error");memset(buf, 0, sizeof(buf));}}close(clientfd);exit(EXIT_SUCCESS);
}
//client端代码与说明
int main()
{int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1)err_exit("socket error");//填写服务器端口号与IP地址struct sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(8001);serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");if (connect(sockfd, (const struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)err_exit("connect error");char buf[512] = {0};pid_t pid = fork();if (pid == -1)err_exit("fork error");//父进程: socket -> terminalelse if (pid > 0){int readBytes;while ((readBytes = read(sockfd, buf, sizeof(buf))) > 0){cout << buf;memset(buf, 0, sizeof(buf));}if (readBytes == 0)cout << "server connect closed...\nclient exiting..." << endl;else if (readBytes == -1)err_exit("read socket error");kill(pid, SIGUSR1);}//子进程: keyboard -> socketelse if (pid == 0){signal(SIGUSR1, sigHandler);while (fgets(buf, sizeof(buf), stdin) != NULL){if (write(sockfd, buf, strlen(buf)) == -1)err_exit("write socket error");memset(buf, 0, sizeof(buf));}}close(sockfd);exit(EXIT_SUCCESS);
}

完整代码实现:

http://download.csdn.net/detail/hanqing280441589/8460013

Socket编程实践(4) --多进程并发server相关推荐

  1. Socket编程实践(10) --select的限制与poll的使用

    select的限制 用select实现的并发服务器,能达到的并发数一般受两方面限制: 1)一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n(number)来调整或 ...

  2. Socket编程实践(6) --TCP服务端注意事项

    僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...

  3. 计算机网络套接字编程实验-TCP多进程并发服务器程序与单进程客户端程序(简单回声)

    1.实验系列 ·Linux NAP-Linux网络应用编程系列 2.实验目的 ·理解多进程(Multiprocess)相关基本概念,理解父子进程之间的关系与差异,熟练掌握基于fork()的多进程编程模 ...

  4. Socket编程实践(12) --UDP编程基础

    UDP特点 无连接,面向数据报(基于消息,不会粘包)的数据传输服务; 不可靠(可能会丢包, 乱序, 重复), 但因此一般情况下UDP更加高效; UDP客户/服务器模型 UDP-API使用 #inclu ...

  5. C# socket编程实践——支持广播的简单socket服务器

    在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# socket编程基本知识,写一个支持广播的简单server/clie ...

  6. Linux网络编程基础<多进程并发服务器>

    一.应用场景 最简单的socket示列代码只能一个客户端连接一个服务器,并不支持多个客户端对服务器的连接,为了能让多个客户端进行连接所以需要多进程或者多线程处理 二.思路解析 服务器端的程序是俩个套接 ...

  7. Socket编程实践(11) --epoll原理与封装

    常用模型的特点 Linux 下设计并发网络程序,有典型的Apache模型(Process Per Connection,PPC), TPC(Thread Per Connection)模型,以及 se ...

  8. Socket编程实践(13) --UNIX域协议

    UNIX域协议 UNIX域套接字与TCP相比, 在同一台主机上, UNIX域套接字更有效率, 几乎是TCP的两倍(由于UNIX域套接字不需要经过网络协议栈,不需要打包/拆包,计算校验和,维护序号和应答 ...

  9. Socket编程实践(5) --TCP粘包问题与解决

    TCP粘包问题 由于TCP协议是基于字节流且无边界的传输协议, 因此很有可能产生粘包问题, 问题描述如下 对于Host A 发送的M1与M2两个各10K的数据块, Host B 接收数据的方式不确定, ...

最新文章

  1. vue开发环境和生产环境里面解决跨域的几种方法
  2. python os.walk()
  3. 【详细解析】7-1 两个有序序列的中位数 (25 分)
  4. matlab怎么计算行列式,Matlab 线性代数(一)–行列式与方程组求解 | 学步园
  5. vue v2.5.0源码-初始化流程
  6. java设计智慧教室_物联网智慧教室设计方案,更便捷的智慧教学体验
  7. 想做C++软件开发工程师,我该如何去学习?
  8. 移动物联卡资费标准是如何的
  9. Jenkins 配置mirrors
  10. python计算机器人运动学分析_orocos_kdl学习(二):KDL Tree与机器人运动学
  11. 每个人心里一亩一亩田,每个人心中一个一个梦
  12. 一加 Ace 竞速版什么时候发布 一加 Ace 竞速版配置怎么样
  13. react中配置less-loader报错
  14. Robot fish: bio-inspired fishlike underwater robots 阅读笔记 1
  15. Dynamic DMA mapping Guide
  16. 华为大数据云issues
  17. 一文带你弄懂C++中的ANSI、Unicode和UTF8三种字符编码及相互转换
  18. 人工神工机器人是什么_全球首台“纯意念控制”机器人在津发布
  19. 映美Jolimark FP-650K 打印机驱动
  20. 如何在Eero路由器上设置静态IP地址

热门文章

  1. 【README】回溯算法基本框架
  2. [Python]网络爬虫(九):百度贴吧的网络爬虫(v0.4)源码及解析
  3. IoT安全系列-如何发现攻击面并进行测试(物联网安全)
  4. web靶机:kali linux 2.0下搭建DVWA渗透测试演练平台
  5. 31. 脱壳篇-什么是壳
  6. matlab实现三次样条插值
  7. vue新增属性是否会响应式更新?
  8. Java内部类详解(Mark)
  9. 如何执行字符串的PHP代码
  10. BZOJ_1601_[Usaco2008_Oct]_灌水_(最小生成树_Kruskal)