网络编程:服务端处理多个客户端----多进程实现、两次fork避免僵尸进程

涉及到一些网络编程的基本概念,这里不做解释。

重点集中在用多进程实现,并且两次fork避免僵尸进程。主进程负责监听,孙进程负责与客户端交流。

实现的功能很简单,客户端连接成功后,输入一个整数,服务端返回它的二进制形式。客户端输入0,则主动退出。

服务端代码:

#include <sys/types.h>  
#include <sys/socket.h>  
#include <stdio.h>  
#include <unistd.h>  
#include <string.h>  
#include <arpa/inet.h>  
#include <signal.h>  
#include <sys/wait.h>  
#include <stdlib.h>
  
#define PORT 6666  
#define SIZE 50  
  
int Create_socket()         //创建套接字和初始化以及监听函数  
{  
    int listen_socket = socket(AF_INET, SOCK_STREAM, 0);      //创建一个套接字    
    if(listen_socket == -1)  
    {  
        perror("socket");  
        return -1;  
    }  
    struct sockaddr_in addr;  
    bzero(&addr,sizeof(addr));  
      
    addr.sin_family = AF_INET;  //Internet地址族  
    addr.sin_port = htons(PORT);  //端口号,htons将主机字节序转为网络字节序
    addr.sin_addr.s_addr = htonl(INADDR_ANY);   //IP地址,服务器段不指定IP地址
      
    int ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr));    //连接  
    if(ret == -1)  
    {  
        perror("bind");  
        return -1;  
    }  
      
    ret = listen(listen_socket, 5);   //转变为监听套接字
    if(ret == -1)  
    {  
        perror("listen");  
        return -1;  
    }  
    return listen_socket;  
}  
  
int wait_client(int listen_socket)  
{  
    struct sockaddr_in cliaddr;  
    int addrlen = sizeof(cliaddr);  
    int client_socket = accept(listen_socket, (struct sockaddr *)&cliaddr, &addrlen);//得到和客户端交流的套接字  
    if(client_socket == -1)  
    {  
        perror("accept");  
        return -1;  
    }  
      
    printf("接收到一个客户端哈:%s\n",inet_ntoa(cliaddr.sin_addr));  
      
    return client_socket;  
}  
  
void talk_client(int client_socket)    //与客户端交流,将客户端传来的数据处理 
{  
    char buf[SIZE];  
    while(1)  
    {  
        int ret = read(client_socket, buf, SIZE-1);  
        if(ret == -1)  
        {  
            perror("read");  
            break;  
        }  
        if(ret == 0)  
        {  
            break;  
        }  
	buf[ret] = '\0';
	int temp = atoi(buf);
	if(temp == 0)
	    break;
        int i = 0;  
	int count = 32;
	while(count--)
	{
	    if(1<< count & temp )
		buf[i++] = '1';
	    else
		buf[i++] = '0';
	    if(count %8 == 0)
		buf[i++] = ' ';
	}

        buf[i] = '\0';  
        printf("%s\n", buf);  
        write(client_socket, buf, i+1);  
    }  
    printf("客户端退出啦哈\n");
    close(client_socket);  
}  
  
int main()  //主进程负责监听,子进程负责与客户端交流
{  
    int listen_socket = Create_socket();  
    while(1)  
    {  		
	int client_socket = wait_client(listen_socket);
	int pid = fork();
	if(pid < 0)
	{
	    perror("fail fork");
	    break;
	}		
	else if(pid == 0)//子进程进来
	{
	    if(( pid = fork()) < 0)
	    {
	        perror("child process fail fork");
	        break;
	    }
	    else if (pid > 0)
	        exit(0);//子进程退出,由init来接管孙进程,避免僵尸进程
	    talk_client(client_socket); //孙进程完成和客户端的交流 
            break;  
	}
	else//主进程进来
	{
	    close(client_socket);//把主进程的交流套接字关掉,以免和孙进程冲突
	}
    }
    close(listen_socket);  
    return 0;  
}  

客户端:

 #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>


#define PORT 6666
#define SIZE 50
int main()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1)
    {
	perror("socket\n");
	return -1;
    }
    struct sockaddr_in addr;
    bzero(&addr,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    char c[] = "127.0.0.1";
    inet_pton(AF_INET,c,(void *)&addr.sin_addr);
    int ret = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
    if(ret == -1)
    {
	perror("connect\n");
	return -1;
    }
    printf("客户端连接成功了哈\n");
    char buf[SIZE];
    while(1)
    {
	printf("请输入你想输入的:");
	scanf("%s",buf);
	write(sockfd,buf,strlen(buf));
	if(atoi(buf) == 0)
	    break;
	int ret = read(sockfd,buf,sizeof(buf));
	if(ret == -1)
	{		
	    perror("read\n");
	    return -1;
	}
	buf[ret] = '\0';
	printf("二进制形式:%s\n",buf);
    }
    close(sockfd);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/znzxc/article/details/80303559