关于多进程并发TCP套接字服务器(C语言)的一些困惑,求助

lkcool7 2016-08-10 11:32:47
下面有一段并发回射服务器
我把我不理解的地方,标在下面代码后了,主要就是服务器在产生子进程后,子进程中的已连接套接字和父进程中已连接的套接字的关系不能理解清楚。希望有朋友能指迷点津,有链接和推荐资料就最好了,提前谢过了。

**************************************************
//linux平台下的并发服务器代码

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
int listenfd,connfd;
struct sockaddr_in servaddr,cliaddr;
pid_t pid;
char buf[4096];
int n,len;
if(argc<2)
{
printf("usage: %s portnumber\n",argv[0]);
return -1;
}
if ((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket");
exit(EXIT_FAILURE);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(atoi(argv[1]));
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
if(bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr))<0)
{
perror("bind");
exit(EXIT_FAILURE);
}
listen(listenfd,20);
while(1)
{
len=sizeof(cliaddr);
printf("server waiting...\n");
if ((connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&len))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0)
{
perror("fork error!");
exit(0);
}
if ( pid == 0)
{
/*为什么在子进程中关掉监听套接字后,主进程监听功能不受影响*/
close(listenfd);
n = read(connfd,buf,sizeof(buf)-1);

buf[n] = 0;
printf("in child process %s\n", buf);
printf("%d connfd =%d\n", n, connfd);
write(connfd,buf,n);
/*主进程中的connfd和子进程中的connfd值是一样的,为什么要在子进程中还要关一次connfd呢? */
close(connfd);
exit(0)
}
/*为什么在主进程中要关掉描述符为connfd套接字后,子进程可以不受影响的从描述符为connfd的套接字中读取数据,在主进程中close(connfd)后,服务器和客户端套接字不是已经断开连接了么*/
close(connfd);
}
}
***************************************************
最后还有一问,在父进程产生子进程后,父进程中已连接套接字、子进程的已连接套接字和客户端的那个套接字,之间的关系是什么样的呢,客户端套接字难道和子父进程的套接字都建立了连接(1对2)?
...全文
453 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
hlx_beat 2016-08-17
  • 打赏
  • 举报
回复
fork 写时拷贝 close会减少一个引用计数 写时拷贝:linux中不强调线程 fork出来的子进程会共享父进程的东西仅仅供读 如果是内核对象那么就是引用计数+1 非内核对象,比如:int i=1; 子进程也是i也是1,如果子进程赋值i=2 不会影响父进程的值
slmax1 2016-08-16
  • 打赏
  • 举报
回复
解决了就给分吧,,嘿嘿,凑个热闹
lkcool7 2016-08-15
  • 打赏
  • 举报
回复
引用 7 楼 pengzhixi的回复:
额 如果父进程没有设置FD_CLOEXEC那么意味着子进程会继承父进程的描述符。 也就意味着描述符对应的底层结构的引用计数会是2.这就是说你需要在父子进程都关闭相应描述符才会真正释放底层的结构。这也就解释了为什么关闭父进程或者子进程的描述符不会影响对方使用该描述符。
我现在懂了,file结构体中,有个记录引用次数的成员,当数目捡到零时就释放内存中打开文件所对应的资源。 谢谢回答
pengzhixi 2016-08-15
  • 打赏
  • 举报
回复
额 如果父进程没有设置FD_CLOEXEC那么意味着子进程会继承父进程的描述符。 也就意味着描述符对应的底层结构的引用计数会是2.这就是说你需要在父子进程都关闭相应描述符才会真正释放底层的结构。这也就解释了为什么关闭父进程或者子进程的描述符不会影响对方使用该描述符。
lkcool7 2016-08-14
  • 打赏
  • 举报
回复 1
一个朋友针对我的问题推荐给我的文章,觉得写的不错,我把它发在这里供有同样问题的朋友学习, http://m.blog.csdn.net/article/details?id=9162453 题目:linux系统文件描述符file descriptor与inode的相关知识
lkcool7 2016-08-14
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
了解一下操作系统的相关概念。
好,谢谢提醒
赵4老师 2016-08-12
  • 打赏
  • 举报
回复
了解一下操作系统的相关概念。
spaceman10 2016-08-12
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
了解一下操作系统的相关概念。
还有tcp协议的知识
lkcool7 2016-08-11
  • 打赏
  • 举报
回复
引用 1 楼 qq_34566286的回复:
子进程只是复制父进城的东西,fork之后子进程内部实现与父进城内部实现没关系。他们共享文件描述符表。子进程关闭连接文件描述浮表。只是把这个链接地址的引用计数减一。《表述不好,看不懂全当我放屁了》
请再多说一点吧,父子进程共享文件描述符表是什么意思,谢谢
qq_34566286 2016-08-11
  • 打赏
  • 举报
回复
子进程只是复制父进城的东西,fork之后子进程内部实现与父进城内部实现没关系。他们共享文件描述符表。子进程关闭连接文件描述浮表。只是把这个链接地址的引用计数减一。《表述不好,看不懂全当我放屁了》
linux C语言 网络编程教程及源码 一、网络应用层编程 1、Linux网络编程01——网络协议入门 2、Linux网络编程02——无连接和面向连接的区别 3、Linux网络编程03——字节序和地址转换 4、Linux网络编程04——套接字 5、Linux网络编程05——C/S与B/S架构的区别 6、Linux网络编程06——UDP协议编程 7、Linux网络编程07——广播 8、Linux网络编程08——多播 9、Linux网络编程09——TCP编程之客户端 10、Linux网络编程10——TCP编程之服务器 11、Linux网络编程11——tcp、udp迭代服务器 12、Linux网络编程12——tcp三次握手、四次挥手 13、Linux网络编程13——connect()、listen()和accept()三者之间的关系 14、Linux网络编程14——I/O复用之select详解 15、Linux网络编程15——I/O复用之poll详解 16、Linux网络编程16——I/O复用之epoll详解 17、Linux网络编程17——tcp并发服务器多进程) 18、Linux网络编程18——tcp并发服务器(多线程) 19、Linux网络编程——tcp高效并发服务器(select实现) 20、Linux网络编程——tcp高效并发服务器(poll实现) 21、Linux网络编程——tcp高效并发服务器(epoll实现) 二、网络底层编程(黑客模式) 1、Linux网络编程1——啥叫原始套接字 2、Linux网络编程2——原始套接字编程 3、Linux网络编程3——原始套接字实例:MAC头分析 4、Linux网络编程4——原始套接字实例:MAC地址扫描器 5、Linux网络编程5——IP数据报格式详解 6、Linux网络编程6——TCP、UDP数据包格式详解 7、Linux网络编程7——原始套接字实例:发送UDP数据包 8、Linux网络编程8——libpcap详解 9、Linux网络编程9——libnet详解
第一篇 基础知识篇  第一章 文件系统和进程系统  1.1 文件系统  1.1.1 文件系统的总体结构  1.1.2 文件结构和目录结构  1.2 文件系统的相关编程  1.3 进程系统  1.3.1 进程的概念  1.3.2 Linux中描述进程的核心数据结构。  1.3.3 和进程相关的系统调用  本章小结 第二章 进程间通信和同步  2.1 信号的处理  2.1.1 Linux中支持的信号  2.1.2 信号的捕获和处理  2.1.3 系统调用和信号的相互作用  2.1.4 pause和suspend函数  2.2 信号量  2.2.1 进程间的互斥  2.2.2 信号量的结构和信号量操作函数 . 2.2.3 应用示例  2.3 消息队列  2.3.1 消息队列的结构  2.3.2 消息队列的操作函数  2.3.3 应用示例  2.4 共享内存  2.4.1 共享内存的操作函数  2.4.2 应用示例  本章小结 第三章 TCP/IP协议  3.1 OSI参考模型、协议和服务  3.2 协议和服务  3. 2.1 TCB/IP  3.2.2 TCP和UDP的比较  3.2.3 Internet上两主机进程间通信数据的封装和解包  3.2.4 IP地址、网络地址和网络掩码  3.2.5 传输层端口  3. 3 域名系统  3.4 域名解析和名字服务器  3. 4. 1 TCP协议  3.4.2 TCP的确认和超时重发机制  3.4.3 TCP头部格式(HeaderFFormat)  3.4.4 TCP连接的状态转移过程  3.5 IP数据包格式  3.6 Internet消息控制协议  本章小结 第二篇 初级应用篇  第四章 基本套接字编程实践  4.1 基本套接字函数族  4.1.1 socket编程的基本流程  4.1.2 函数socket  4.1. 3 函数connect  4.1. 4 函数bind  4.1.5 函数listen  4.1.6 函数accept  4.1.7 函数read和write  4.1.8 函数close  4.2 应用示例  4.3 程序结果和异常说明  4.3.1 程序的运行结果  4.3. 2 程序的异常  本章小结  第五章 无阻塞套接字和单进程轮询服务器  5.1 无阻塞套接字  5.1.1 阻塞套接字的缺点  5.1. 2 阻塞和无阻塞的比较  5.1.3 无阻塞的实现  5.2 单进程轮询服务器工作方式  5. 3 应用示例  5.3.1 应用说明  5.3.2 应用源码  第六章 带外数据与多路复用、信号驱动的输入J输出模型  6.1 多路复用的输入/输出模型  6.1.1 多路复用模型的概念与select函数  6.1.2 应用示例  6.1.3 pselect函数对select的增强  6.2 信号驱动的输入/输出模型  6.3 系统I/O模型的总结  6.4 带外数据  6.4.1 带外数据的发送  6.4.2 带外数据的接收  6.4.3 带外数据接收方法的示例  本章小结  第七章 UDF数据报  7.1 UDP数据报的概述  7.2 UDP通信的过程  7.3 UDP的服务器TCP服务器的比较  7.4 UDP的“连接”  7.5 应用示例  本章小结  第八章 域名系统和通用套接字选项  8.1 域名系统  8.1.1 域名系统的回顾  8.1.2 通过地址获取主机信息  8.1.3 通过主机名获取主机信息  8.1.4 获取本地主机的信息  8.1.5 通过服务名获取服务端口  8.1.6 通过端口号获取服务名  8.2 套接字选项  8.2.1 获取和设置套接字选项  8.2.2 通用套接字选项  本章小结 第三篇 应用提高篇  第九章 高级套接字函数编程实践  9.1 函数recv和send  9.1.1 函数send  9.1.2 函数recv  9.1.3 应用示例  9.1.4 应用源码和分析  9.2 函数readv和writev  9.2.1 函数说明  9.2.2 应用示例  9.3 函数比recvmsg和sendmsg  本章小结  第十章 守护进程和超级服务器inetd  10.1 守护进程的原理  10.2 编程实践  10.3 超级服务器inetd的工作原理  10.3.1 超级服务器的概念  10.3.2 超级服务器使用的配置文件  10.3.3 inetd处理并发服务的过程  本章小结  第十一章 数据结构的传输和xDR标准  11.1 数据结构的传送  11.1.1 数据结构传送的问题  11.1.2 简单的示例  11.2 XDR标准  11.2.1 XDR中包含的数据类型  11.2.2 XDR实现的原理  11.2.3 XDR的转换函数库  本章小结  第十二章 BPC远程过程调用原理和实践  12.1 RPC的原理  12.1.1 XDR的更进一步  12.1.2 本地函数调用的过程  12.1.3 用远程调用来虚拟本地调用  12.2 RPC的实现  12.2.1 远程过程的标识  12.2.2 端口的动态映射  12.2.3 RPC的报文  12.2.4 RPC开发工具  12.2.5 设计的原则  12.3 应用示例:网络记事本  12.3.1 编写本地应用  12.3.2 Rpcgen构建RPC应用  12.3.3 编写RPC说明文件  12.3.4 修改客户端程序  12.3.5 修改服务器端程序  12.3.6 调用的完整过程  12.3.7 程序的结果、分析和总结  本章小结 第四篇 高级编程篇  第十三章 UNIX域套接字并发服务器的预创建技术  13.1 UNIX域套接字  13.1.1 UNIX域的地址结构  13.1.2 UNIX(套接字使用的示例  13.1.3 传递文件描述符  13.2 并发服务器的预创建技术  13.2.1 预创建固定服务器进程的数量  13.2.2 动态的管理子进程  13.2.3 重用服务器子进程  本章小结  第十四章 原始套接字编程实践  14.1 原始套接字  14.1.1 原始套接字的创建  14.1.2 原始套接字的使用  14.1.3 IP包头和ICMP报文的C语言描述  14.2 Ping应用程序  14.2.1 程序设计  14.2.2 程序源码  14.3 IP套接字选项  14.3.1 IP_TTL选项  14.3.2 IP_TOS选项  14.3.3 IP_OPTIONS选项  14.3.4 IP_HDRINCL选项  本章小结  第十五章 多线程编程  15.1 线程的概念  15.1.1 线程的概念  15.1.2 线程的分类  15.1.3 线程的创建和等待函数  15.1.4 线程的属性函数  15.2 线程间的同步  15.2.1 无名信号量  15.2.2 互斥锁、条件变量和条件信号  15.2.3 线程和信号  15.3 在网络程序中应用多线程  15.3.1 线程间参数的传递  15.3.2 线程安全函数的设计  15.3.3 多进程并发服务器和多线程的并发服务器  15.3.4 客户端进程的多线程化  本章小结 第十六章 网络售票系统的简单模拟  16.1 系统的总体设计  16.1.1 应用的说明  16.1.2 数据格式的设计  16.1.3 服务器端的设计  16.1.4 客户端的设计  16.2 程序源码和解析  16.2.1 服务器端的源码  16.2.2 客户端的源码  本章小结

69,335

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧