网络服务器通常fork来处理来同时服务多个客户端 ,父进程 监听端口, accpet 后 fork一个子进程专门服务这个客户端 。 由于子进程退出时 会产生僵尸进程 ,父进程要注意处理SIGCHILD信号,和调用wait清理僵尸进程,亦可直接忽略SIGCHILD信号。
思路框图 :
服务器端 代码 :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#define MAXLINE 1024
#define ClientNum 256
#define Port_Number 6666
void do_Sevivce(int fd);
int main()
{
signal(SIGCHLD,SIG_IGN); //忽略SIGCHILD
int n,listenfd,cnectfd; //
char buf[MAXLINE];
struct sockaddr_in servaddr;
pid_t pid;
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd < 0)
{
perror("Listen error:");
exit(0);
}
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(Port_Number);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int on = 1;
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
{//closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
perror("Setsockopt error :");
exit(0);
}
if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)
{
perror("Bind error :");
exit(0);
}
if(listen(listenfd,10)<0)
{
perror("Listen error :");
exit(0);
}
struct sockaddr_in clientaddr; //传出参数,用于填充客户端地址
socklen_t addrlen = sizeof(clientaddr); //传入传出参数,必须有初值,地址长度
int clientfd;
while(1)
{
if((clientfd = accept(listenfd,(struct sockaddr *)&clientaddr,&addrlen))<0)
{
perror("accept error :");
}
printf("recv connect ip=%s port=%d\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
pid = fork();
if(pid == -1)
perror("fork error");
if(pid==0)
{
close(listenfd); //子进程已经用不到监听描述符,故将其关闭
do_Sevivce(clientfd);
exit(EXIT_SUCCESS);
}
else
close(clientfd);
}
return 0;
}
void do_Sevivce(int fd)
{
char recvbuf[1024];
while(1)
{
memset(recvbuf,0,sizeof(recvbuf));
int ret = read(fd,recvbuf,sizeof(recvbuf));
if(ret == 0) //客户端闭了
{
printf("client close\n");
break;
}
else if(ret == -1)
{
perror("read error :");
exit(0);
}
fputs(recvbuf,stdout);
write(fd,recvbuf,ret);
}
}
客户端代码 :
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<signal.h>
#define Port_Number 6666
#define BUFFSIZE 1024
void handler(int sig)
{
printf("recv a sig=%d\n",sig);
exit(EXIT_SUCCESS);
}
int main()
{
int sockfd; //被动套接字(文件描述符),即只可以accept
if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket error :");
}
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(Port_Number);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)
{
perror("Connect error :");
}
char sendbuf[BUFFSIZE];
char recvbuf[BUFFSIZE];
while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
{
write(sockfd,sendbuf,strlen(sendbuf));
read(sockfd,recvbuf,sizeof(recvbuf));
fputs(recvbuf,stdout);
memset(sendbuf,0,sizeof(sendbuf));
memset(recvbuf,0,sizeof(recvbuf));
}
close(sockfd);
return 0;
}
测设 : 一个终端 打开服务器 ,
另外开两个终端 打开客户端发送数据。