下面有一段并发回射服务器
本人把本人不理解的地方,标在下面代码后了,主要就是服务器在产生子进程后,子进程中的已连接套接字和父进程中已连接的套接字的关系不能理解清楚。希望有朋友能指迷点津,有链接和推荐资料就最好了,提前谢过了。
**************************************************
//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)?
本人把本人不理解的地方,标在下面代码后了,主要就是服务器在产生子进程后,子进程中的已连接套接字和父进程中已连接的套接字的关系不能理解清楚。希望有朋友能指迷点津,有链接和推荐资料就最好了,提前谢过了。
**************************************************
//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)?
解决方案
20
子进程只是复制父进城的东西,fork之后子进程内部实现与父进城内部实现没关系。他们共享文件描述符表。子进程关闭连接文件描述浮表。只是把这个链接地址的引用计数减一。《表述不好,看不懂全当本人放屁了》
5
了解一下操作系统的相关概念。
15
额 假如父进程没有设置FD_CLOEXEC那么意味着子进程会继承父进程的描述符。 也就意味着描述符对应的底层结构的引用计数会是2.这就是说你需要在父子进程都关闭相应描述符才会真正释放底层的结构。这也就解释了为什么关闭父进程或子进程的描述符不会影响对方使用该描述符。
10
fork 写时拷贝 close会减少一个引用计数
写时拷贝:linux中不强调线程 fork出来的子进程会共享父进程的东西仅仅供读 假如是内核对象那么就是引用计数+1
非内核对象,例如:int i=1; 子进程也是i也是1,假如子进程赋值i=2 不会影响父进程的值
写时拷贝:linux中不强调线程 fork出来的子进程会共享父进程的东西仅仅供读 假如是内核对象那么就是引用计数+1
非内核对象,例如:int i=1; 子进程也是i也是1,假如子进程赋值i=2 不会影响父进程的值