Linux socke server编程:父进程和子进程关系

Linux socke server编程:父进程和子进程关系

  • 测试过程中碰到的需要记录的地方
  • 完整代码
  • 注意点

测试过程中碰到的需要记录的地方

1、父进程accept创建新socket后(比如socket为connect_fd),需要在父进程中关闭该connect_fd(即close(connect_fd))(父进程负责accept等待创建连接,每次产生新的连接交给子进程处理的情况下)
因为:子进程是父进程的完全拷贝,所以只有父子两个进程都关掉connect_fd,这个connect_fd才算关掉;如果父进程这里没有close(connect_fd),那就算子进程close(connect_fd),实际socket connect_fd并没有被关闭; 所以为了子进程完全控制connect_fd,父进程创建connect_fd后,直接close(connect_fd);

完整代码

下面展示 TCP server端代码

/* File Name: server.c */  
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<errno.h>  
#include<sys/types.h>  
#include<unistd.h>/*#包含 fork()等程序会用到*/
#include<arpa/inet.h>/**/
#include<sys/socket.h>  
#include<netinet/in.h>  
#define DEFAULT_PORT 40010  
#define MAXLINE 4096  
int main(int argc, char** argv)  
{
       
	int    socket_fd, connect_fd;  
	struct sockaddr_in     servaddr;  
	char    buff[4096];  
	int     n;  
	//初始化Socket     
	if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
       
		printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);  
		exit(0);  
	}  
	//初始化  
	memset(&servaddr, 0, sizeof(servaddr));  
	servaddr.sin_family = AF_INET;  
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。  
	//   printf("servaddr.sin_addr_cxf == %s\n",inet_ntoa((struct in_addr) servaddr.sin_addr)); 
	servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT  

	//将本地地址绑定到所创建的套接字上  
	if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
       
		printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);  
		exit(0);  
	}  
	//开始监听是否有客户端连接  
	if( listen(socket_fd, 10) == -1){
       
		printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);  
		exit(0);  
	}  
	printf("======waiting for client's request======\n");  
	printf("main PID == %d\n",getpid());
	while(1){
       
		//阻塞直到有客户端连接,不然多浪费CPU资源。  
		if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){
       
			printf("accept socket error: %s(errno: %d)",strerror(errno),errno);  
			continue;  
		}		
		if(!fork())
		{
     
			printf("son PID == %d\n",getpid());
			printf("connect_fd == %d\n",connect_fd); 
			if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1)  
				perror("send error");
			while(1)
			{
     
				//接受客户端传过来的数据  
				if((n = recv(connect_fd, buff, MAXLINE, 0))== 0)                  //这里要判断recv接收到的是否为0,不然client主动断开后,会导致一直打印"recv msg from client: %s,PID:%d \n"
				{
     
					printf("closed from client,connect_fd:%d\n",connect_fd);
					close(connect_fd);
					exit(0);				
				}
				buff[n] = '\0'; 
				printf("connect_fd:%d \n", connect_fd);  
				printf("recv msg from client: %s,PID:%d \n", buff,getpid());  
			}	
		}
		close(connect_fd);           //这里是父进程的connect_fd,需要着重讲下:父子进程都有这个connect_fd标识符,只有父子两个进程都关掉connect_fd,这个connect_fd才算关掉;如果父进程这里没有close(connect_fd),那就算子进程close(connect_fd),实际socket connect_fd并没有被关闭; 所以为了子进程完全控制connect_fd,父进程创建connect_fd后,直接close(connect_fd)
	}  
	close(socket_fd);  
}  

注意点

1、fork()之后,创建新进程(即子进程),通过sudo netstat -antup可以查看原进程和新进程;
2、可以通过getpid()获取本进程的进程ID(即PID);
3、如果子进程结束,但是子进程的某些资源没关掉的话,会导致进程被挂到父进程下面

比如子进程中没有close(connect_fd),但是子进程调用了exit(0)关闭自己的线程,然后从sudo netstat -antup来看,子线程还在,只不过PID变成了父进程的PID

你可能感兴趣的:(socket,socket,linux,多进程,网络,tcpip)