多进程并发服务器
tcp_process_server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define port 49999
#define ERROR -1
#define Max 1024
static int sfd = 0;
//服务器的初始化操作
int server_init()
{
//建立流式套接字
sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd == -1){
perror("socket()");
goto ERR_SET;
}
//服务器的地址结构
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = htonl(INADDR_ANY),//INADDR_ANY获取系统地址
};
//服务器的地址长度
socklen_t len = sizeof(struct sockaddr_in);
//绑定服务器地址
if(bind(sfd,(struct sockaddr *)&server_addr,len) < 0){
perror("bind()");
goto ERR_SET;
}
//设置监听套接字
if(listen(sfd,10) < 0){
perror("listen()");
goto ERR_SET;
}
return sfd;
ERR_SET:
close(sfd);
return ERROR;
}
//接收客户端的数据
int do_reply_client(int fd)
{
char buf[Max] = {0};
memset(buf,0,sizeof(buf));
while(1){
int nByte = recv(fd,buf,sizeof(buf),0);
if(nByte < 0){
perror("recv()");
goto ERR_SET;
}else if(nByte == 0){//当nbyte等于0的时候,表示客户端退出
printf("the client is disconnect...\n");
//退出
exit(EXIT_SUCCESS);
}else{
printf("%s\n",buf);
}
}
ERR_SET:
close(fd);
return ERROR;
}
//回收子进程
//当有一个客户端连接服务器的时候,对应的会有一个子进程来处理
//同样的当客户端退出的时候,需要回收对应的子进程
void wait_process(int sig)
{
//回收子进程可以用wait()或者waitpid();
int pid = waitpid(-1,NULL,WNOHANG);
//打印回收的子进程的pid号
printf("wait pid is :%d\n",pid);
}
int main(int argc, const char *argv[])
{
//注册信号,当子进程退出的时候,会发送信号SIGCHLD
//通过指令 kill -l可以查看对应的相关信号
signal(SIGCHLD,wait_process);
//服务器初始化
int fd = server_init();
//客户端地址信息
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
printf("waiting for connect...\n");
int cfd = 0;
//等待客户端链接
while(1){
cfd = accept(fd,(struct sockaddr *)&client_addr,&len);
if(cfd < 0){
perror("accept()");
goto ERR_SET;
}
//打印客户端的ip和port
//printf("the client ip is %s\n",inet_ntoa(client_addr.sin_addr));
//printf("the client port is %d\n",ntohs(client_addr.sin_port));
//链接一个客户端,建立一个子进程,处理客户端的数据
pid_t pid = fork();
if(pid < 0){
perror("fork()");
return ERROR;
}else if(pid == 0){//子进程处理对应的客户端信息
//打印子进程的pid号
printf("the child process pid is %d\n",getpid());
do_reply_client(cfd);
}
}
return 0;
ERR_SET:
close(fd);
return ERROR;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#define ERROR -1
#define Max 1024
//服务器的ip地址和端口号
const char *ip = "127.0.0.1";
const ushort port = 49999;
int main(int argc,const char *argv[])
{
//建立流式套接字
int server_fd = socket(AF_INET,SOCK_STREAM,0);
if(server_fd == -1){
perror("socket()");
goto ERR_STEP;
}
//服务器的地址结构
//inet_addr将字符串形式的ip地址转换成网络字节序的整型值
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = inet_addr(ip),
};
//服务器的地址长度
socklen_t len = sizeof(server_addr);
//连接服务器
if((connect(server_fd,(struct sockaddr*)&server_addr,len))< 0){
perror("connect");
goto ERR_STEP;
}else{
printf("connect successed\n");
}
//循环发送数据
while(1){
//写缓冲区
char buf[Max] = {0};
memset(buf,0,sizeof(buf));
scanf("%s",buf);
int ret = write(server_fd,buf,sizeof(buf));
if(ret < 0){
perror("write");
goto ERR_STEP;
}
}
ERR_STEP:
close(server_fd);
return ERROR;
}
实验效果: