Linux socke server程式設計:父程式和子程式關係

chaixiongfeng發表於2021-01-03

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>/*#包含<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

相關文章