多线程处理
服务器端
accept()放在线程函数中可能会造成的问题:
有可能多个线程同时去已完成三次握手的队列中建立链接,这时候需要加锁。以保证互斥的访问。
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
void *thread_fun(void *arg)
{
int c=(int)arg;
while(1)
{
char buff[128]={0};
int n=recv(c,buff,127,0);
if(n<=0)
{
break;
}
printf("rccv(%d)=%s\n",c,buff);
send(c,"ok",2,0);
}
close(c);
printf("one client over\n");
}
int main()
{
pthread_t thread;
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);//1024 root,4096 reserve,5000+ tempary
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
assert(res!=-1);
listen(sockfd,5);//create listen queue
while(1)
{
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr *)&caddr,&len);
if(c<0)
{
continue;
}
printf("accept c=%d,ip=%s,port=%d\n",c,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
pthread_create(&thread,NULL,thread_fun,(void *)c);
}
close(sockfd);
}
客户端
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
assert(res!=-1);
while(1)
{
char buff[128]={0};
printf("input:\n");
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);
//write(sockfd,buff,strlen(buff));
memset(buff,0,128);
recv(sockfd,buff,127,0);
printf("buff=%s\n",buff);
}
close(sockfd);
}
多进程处理
服务器端
fork()之后c的引用计数加1,主进程不用,一定要close©
存在的问题:当多个线程在同一时刻结束时,父进程只能处理一个,其他子进程没办法处理,可以采用waitpid()函数进行处理,waitpid()返回值为0,我们可以认为还有僵死进程,接着循环进行处理,否则认为僵死进程已经处理完了,结束循环。
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
void sig_fun(int sig)
{
int val=0;
wait(&val);//收到信号后,等待子进程结束
}
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);//1024 root,4096 reserve,5000+ tempary
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
assert(res!=-1);
listen(sockfd,5);//create listen queue
signal(SIGCHLD,sig_fun);
pid_t pid;
while(1)
{
int len=sizeof(caddr);
int c=accept(sockfd,(struct sockaddr *)&caddr,&len);
if(c<0)
{
continue;
}
printf("accept c=%d,ip=%s,port=%d\n",c,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
pid=fork();
if(pid==-1)
{
close(c);
continue;
}
if(pid==0)
{
while(1)
{
char buff[128]={0};
int n=recv(c,buff,127,0);
if(n<=0)
{
break;
}
printf("buff=%s\n",buff);
send(c,"ok",2,0);
}
close(c);
printf("one client over\n");
exit(0);
}
close(c);
}
close(sockfd);
exit(0);
}
客户端
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=connect(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
assert(res!=-1);
while(1)
{
char buff[128]={0};
printf("input:\n");
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
send(sockfd,buff,strlen(buff),0);
//write(sockfd,buff,strlen(buff));
memset(buff,0,128);
recv(sockfd,buff,127,0);
printf("buff=%s\n",buff);
}
close(sockfd);
}