1、多进程并发服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line=%d\n",__LINE__);\
perror(msg);\
}while(0)
int deal_clientmsg(int newfd,struct sockaddr_in cin);
typedef void (*sighandler_t)(int);
void handler(int sig)
{
while(waitpid(-1,NULL,WNOHANG)>0);
}
#define PORT 8878
#define IP "192.168.52.183"
int main(int argc, const char *argv[])
{
//捕捉17号信号回收僵尸进程
sighandler_t s=signal(17,handler);
if(SIG_ERR==s)
{
ERR_MSG("signal");
return -1;
}
//创建流式套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR_MSG("socket");
}
//填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;//必须填AF_INET
sin.sin_port=htons(PORT);//网络字节序的端口地址
sin.sin_addr.s_addr=inet_addr(IP);//点分十进制转换成网络字节序
//绑定服务器的IP和端口
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
//将套接字设置成被动监听状态
if(listen(sfd,10)<0)
{
ERR_MSG("listen");
return -1;
}
//存储哪里发送的信息
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
pid_t pid;
while(1)
{
//客户端连接后返回新的文件描述符
//父进程只负责处理连接
int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(newfd<0)
{
ERR_MSG("accept");
return -1;
}
printf("[%s:%d]%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
//到这里说明已经有客户端进行连接了,子进程要处理与客户端的交互
pid=fork();
if(pid==0)
{
//子进程
close(sfd);
deal_clientmsg(newfd,cin);
exit(0);//交互结束后要退出子进程
}
else if(pid>0)
{
//父进程
close(newfd);
}
else
{
ERR_MSG("fork");
return -1;
}
}
close(sfd);
return 0;
}
int deal_clientmsg(int newfd,struct sockaddr_in cin)
{
char buf[128]="";
ssize_t ret=0;
while(1)
{
bzero(buf,sizeof(buf));
//循环接收客户端发送的消息
ret=recv(newfd,buf,sizeof(buf),0);
if(ret<0)
{
ERR_MSG("recv");
return -1;
}
if(ret==0)
{
printf("对端退出\n");
break;
}
printf("[%s:%d]%d %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf);
//给客户端发送信息
if(send(newfd,buf,sizeof(buf),0)<0)
{
ERR_MSG("send");
return -1;
}
printf("发送成功\n");
}
close(newfd);
}
//运行结果
ubuntu@ubuntu:review$ gcc 03_pidtcpser.c
ubuntu@ubuntu:review$ ./a.out
[192.168.52.1:60498]4
[192.168.52.1:60498]4 111
发送成功
[192.168.52.1:60501]4
[192.168.52.1:60501]4 222
发送成功
对端退出
对端退出
2、多线程并发服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line=%d\n",__LINE__);\
perror(msg);\
}while(0)
#define PORT 8888
#define IP "192.168.52.183"
struct mess
{
int newfd;
struct sockaddr_in cin;
};
void *deal_clientmsg(void *arg);//void *arg=void *info
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR_MSG("socket");
}
//填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;//必须填AF_INET
sin.sin_port=htons(PORT);//网络字节序的端口地址
sin.sin_addr.s_addr=inet_addr(IP);//点分十进制转换成网络字节序
//绑定服务器的IP和端口
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
//将套接字设置成被动监听状态
if(listen(sfd,10)<0)
{
ERR_MSG("listen");
return -1;
}
//存储哪里发送的信息
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
pthread_t tid;
while(1)
{
//客户端连接后返回新的文件描述符
//主线程负责处理连接
int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(newfd<0)
{
ERR_MSG("accept");
return -1;
}
printf("[%s:%d]%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
struct mess info;
info.newfd=newfd;
info.cin=cin;
//运行到这里,说明有客户端连接成功,需创建分支线程处理与客户端的交互
if(pthread_create(&tid,NULL,deal_clientmsg,&info)<0)
{
ERR_MSG("pthread_create");
return -1;
}
pthread_detach(tid);
}
close(sfd);
return 0;
}
void *deal_clientmsg(void *arg)//void *arg=void *info
{
struct mess info=*(struct mess*)arg;
int newfd=info.newfd;
struct sockaddr_in cin=info.cin;
char buf[128]="";
ssize_t ret=0;
while(1)
{
bzero(buf,sizeof(buf));
//循环接收客户端发送的消息
ret=recv(newfd,buf,sizeof(buf),0);
if(ret<0)
{
ERR_MSG("recv");
pthread_exit(NULL);
}
if(ret==0)
{
printf("对端退出\n");
break;
}
printf("[%s:%d]%d %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf);
//给客户端发送信息
if(send(newfd,buf,sizeof(buf),0)<0)
{
ERR_MSG("send");
pthread_exit(NULL);
}
printf("发送成功\n");
}
close(newfd);
}
//运行结果
ubuntu@ubuntu:review$ gcc 04_tidtcpser.c -pthread
ubuntu@ubuntu:review$ ./a.out
[192.168.52.1:61039]4
[192.168.52.1:61039]4 111
发送成功
[192.168.52.1:61041]5
[192.168.52.1:61041]5 222
发送成功
[192.168.52.1:61044]6
[192.168.52.1:61044]6 333
发送成功
对端退出
对端退出
对端退出