linux学习笔记11 多进程服务端编程

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

using namespace std;

void recycle(int arg)
{
	pid_t pid;
	while ((pid=waitpid(-1, NULL, WNOHANG))<=0) {}
	cout<<"one child is dying, pid is"<<pid<<endl;
}//接受到SIGCHLD信号时的回收函数
/*并发服务器中,父进程负责接收客户端,子进程负责与客户端通信,每接收到一个客户端,就开一个子进程*/
int main(int argc, const char *argv[])
{
	if (argc<2)
	{
		cout<<"input :./a.out port";
		exit(1);	
	}

	int sfd, cfd;
	int port=atoi(argv[1]);

	char buf[256];
	int n;
/*定义结构体sockaddr,存储服务端的ip和端口*/
	struct sockaddr_in addr_server;
	addr_server.sin_port=htons(port);
	addr_server.sin_addr.s_addr=htonl(INADDR_ANY);
	addr_server.sin_family=AF_INET;

/*定义结构体sigaction,用来捕捉SIGCHLD信号*/	
    struct sigaction act;
	act.sa_handler=recycle;
	act.sa_flags=0;
	sigemptyset(&act.sa_mask);
	sigaction(SIGCHLD, &act, NULL);

	struct sockaddr_in addr_client;
	socklen_t addrlen=sizeof(addr_client);

	sfd=socket(AF_INET, SOCK_STREAM, 0);//建立套接字
	bind(sfd, (struct sockaddr*) &addr_server, sizeof(addr_server));//绑定ip和端口
	listen(sfd, 20);
	//父进程接收连接请求
    // accept阻塞的时候被信号中断, 处理信号对应的操作之后
    // 回来之后不阻塞了, 直接返回-1, 这时候 errno==EINTR	
	while (1)
	{
		cfd=accept(sfd, (struct sockaddr*) &addr_client, &addrlen);
		while (cfd==-1&&errno==EINTR)//当
			cfd=accept(sfd, (struct sockaddr*) &addr_client, &addrlen);
        if (cfd==-1&&errno!=EINTR)
        {
            cout<<"accept is error!";
            exit(1);
        }

		pid_t pid=fork();//当接受到一个客户端以后,打开一个子进程和客户端通信
		if (pid<0)
		{
			cout<<"fork is error!";
			exit(1);
		}
		else if (pid==0)//子进程
		{
			close(sfd);子进程中不再需要接受客户端,所以关闭接受客户端的描述符
			char ip[64];
			while (1)
			{
				cout<<"the client's ip is"<<inet_ntop(AF_INET, &addr_client.sin_addr.s_addr, ip, sizeof(ip))<<"\n";
				cout<<"the client's port is"<<ntohs(addr_client.sin_port)<<"\n";
				int n=read(cfd, buf, sizeof(buf));
				if (n==-1)
				{
					cout<<"read is error!";
					exit(1);
				}else if (n==0)//read是阻塞的,如果返回结果是0, 说明是客户端发送了文件结束符,表明要结束了,不是客户端不发消息就是0
				{
					cout<<"client is over!";
					break;
				}else
				{
					for (int i=0; i<n; i++)
						buf[i]=toupper(buf[i]);
					write(cfd, buf, n);
				}
			}
			return 0;
		}
		else//父进程	 
		{
			close(cfd);父进程不需要用通信的文件描述符,所以关闭
		}
	}
	close(sfd);//能执行到这一步就只有父进程了,父进程的通信描述符已经关闭了,所以只需要关闭接受描述符就行了。
	return 0;
}

现象是首先执行./a.out文件

可以打开多个终端

服务器终端上结果,每次连入一个客户端或者在客户端做一次输入,都会显示一个通信的ip和端口号。

猜你喜欢

转载自blog.csdn.net/qq_34489443/article/details/88371754