实现TCP并发服务器

一、为什么TCP不能实现并发,而UDP可以 

        因为TCP服务器端有两个读阻塞函数,accept和recv,两个函数需要先后运行,所以导致运行一个函数的时候另一个函数无法执行,所以无法保证一边连接客户端,一边与其他客户端通信。

        而UDP只有一个阻塞函数recvfrom,并且无需连接,因此,可以实现并发。

二、如何实现TCP并发服务器

2.1、常用的两种方式

        1、使用多进程实现TCP并发服务器
        2、使用多线程实现TCP并发服务器

三、使用多进程实现TCP并发服务器

3.1、使用多进程实现TCP并发服务器简单流程

 int sockfd = socket()       创建套接字
 bind()                              与套接字绑定自己的信息
 listen()                            将套接字设置为被动监听状态,并设置同时可以连接多少台客户端  
 while(1) {                         循环等待,客户连接
 acceptfd = accept()         接收到客户端的sockfd ,并返回一个专属客户端acceptfd标识符
 pid = fork();                      创建父子进程
 if(pid > 0)                          大于0为父进程
  {         }
 else if(pid == 0)                 等于0为子进程
   {
        while(1)                      与专属的客户端通信
   {
      recv()/send()                 接与收
    }}}

 弊端:进程结束,没有回收资源,造成资源浪费,解决方法,使用signal信号函数回收子进程。

如有不懂,请查看signal信号的章节学习。

3.2、使用多进程实现TCP并发服务器代码实现

3.3、服务器代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>

#define N 128

void handler()
{
	wait(NULL);
	
	
	}


int main(int argc , char *argv[])
{  
  	if(argc<3)
	{
		printf("fail : lose ip port\n");
		exit(1);
		
		}

     int sockfd;

	 signal(SIGCHLD,handler);


   	 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	 {
		 perror("fail to sockfd");
		 exit(1);
		 }
	 struct sockaddr_in mysockaddr;

	 mysockaddr.sin_family=AF_INET;
	 mysockaddr.sin_port = htons(atoi(argv[2]));
	 mysockaddr.sin_addr.s_addr =inet_addr(argv[1]);
     socklen_t addrlen =sizeof(mysockaddr);
   
   
 	 if(bind(sockfd,(struct sockaddr *)&mysockaddr,addrlen)==-1)
     {
		 perror("fail to bind");
		 exit(1);
		 }
	  
	   if(listen(sockfd,5)==-1)
	   {
		    perror("fail to listen");
		    exit(1);
		   }
      
        struct sockaddr_in acceptaddr;
        socklen_t acceptaddrlen=sizeof(acceptaddr);
        pid_t pid;
		int acceptfd;
	   while(1)
	   {
		   
	    if((acceptfd=accept(sockfd,(struct sockaddr*)&acceptaddr,&acceptaddrlen))==-1)
		{
			perror("fail to acceptfd");
			exit(1);
			
			}
		printf("reciver from ip = %s ,port:%d\n",inet_ntoa(acceptaddr.sin_addr),ntohs(acceptaddr.sin_port));


		pid=fork();

		if(pid<0)
		{
			
			perror("fail to fork");
			exit(1);

			}
		   
        else if(pid>0)
		{
			
			}

		  else
		  {

                 ssize_t byte;

			while(1)
			{
				char text[N]="";
				char buf[N]="";
    	        if((byte=recv(acceptfd,buf,N,0))==-1)
				{					
					perror("fail to recv");
					exit(1);
					}

                else if(byte==0)
				 {
					 printf("the client quit\n");
					 exit(1);
					 }
                   

 			    printf("from client :%s\n",buf);
				
                  
				 strcat(text,"^_^") ;

 				if(send(acceptfd,text,N,0)==-1)
				{
				perror("fail to ssend");
				exit(1);
					}
			  
			 } 
		  }	   
		   
		   }

	  return 0;
	}

3.4、 客户端代码

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>       
#include <sys/socket.h>
#include<string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
 
#define N 128
int main(int argc ,char *argv[])
{
	 if(argc<3)
	 {
		 printf("fail ,lose ip port\n");
		 exit(1);
		 
		 }
	 int sockfd;
 
	 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	 {
		 perror("fail to sockfd");
		 exit(1);
		 
		 }
 
//	  printf("TCP:sockfd= %d\n",sockfd);
        
      struct sockaddr_in mysockaddr;
 
	  mysockaddr.sin_family=AF_INET;
	  mysockaddr.sin_port=htons(atoi(argv[2]));
	  mysockaddr.sin_addr.s_addr=inet_addr(argv[1]);
	  socklen_t addrlen= sizeof(mysockaddr);
 
      if(connect(sockfd,(struct sockaddr*)&mysockaddr,addrlen)==-1)
	  {
		   perror("fail to connect");
		   exit(1);
		   }
	   
	  
	     char buf[N]="";
		 char text[N]="";
	while(1)
	{
		  fgets(buf,N,stdin);
          
		  if(send(sockfd,buf,N,0)==-1)
		  {
			  perror("fail to send");
			  exit(1);
			  
			  }
		  
	     
		 if(recv(sockfd,text,N,0)==-1)
		 {
	          perror("fail to recv");
			  exit(1);
 
			 }
		  
		  printf("from server: %s\n",text);
	    	  
       }    		  
		  close(sockfd);
	  
        	return 0;
	
	}
 

3.5、运行结果

 

 四、使用多线程实现TCP并发服务器

4.1、多线程实现TCP并发服务器简单流程

typedef struct {                                           //定义一个结构体

       struct sockaddr_in  addr;                    //用来传给子线程

       int acceptfd;      

} MSG;

  void *thread_fun(void *arg)          
  {    

         MSG msg = *(MSG *)arg;           //客户端的信息,传给子线程

while(1)
  {
      recv() / send()                                 // 接与收
 } }

  sockfd = socket()                               //创建套接字
  bind()                                                 //绑定套接字与自己的信息
  listen()                         // 将套接字设置为被动监听状态,并设置同时可以连接多少台客户端 
    while(1)                       //循环等待 客户端连接
   {
   accept()                        //创建专属对应客户端的acceptfd标识符
    //只要有客户端连接上,则创建一个子线程与之通信
  pthread_create(, , thread_fun, );           
 pthread_detach();              //分离模式,自动回收资源,不等待
 }

 4.2、服务器代码

#include<stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <pthread.h>
#include<string.h>
#include<unistd.h>


#define N 128
typedef struct
{
	struct sockaddr_in addr;
	  int acceptfd ;
	
	
	}MSG;

void * pthread_fun(void *arg)
{
	  char buf[N]="";
	  ssize_t size ;
	 MSG msg = *(MSG *)arg;
     while(1)
	 {
		 char text[N]="";
		 if((size=recv(msg.acceptfd,buf,N,0))==-1)
		 {
			 perror("fail to recv");
			 pthread_exit(NULL);
			 }
		 else if(size ==0)
		 {
			 perror("quit client");
			 pthread_exit(NULL);
			 
			 }
		 printf("[%s ‐ %d]: %s\n", inet_ntoa(msg.addr.sin_addr), ntohs(msg.addr.sin_port), buf);

         strcat(text," ^_^");

         if(send(msg.acceptfd,text,N,0)==-1)
		 {
			 perror("fail to send");
			 exit(1);
			 }
		 }	 
	
	 }

int main(int argc ,char *argv[])
{ 
     if(argc <3)
	 {
		 printf("fail ; lose ip port \n");
		 exit(1);
		 }

	 int sockfd;

	 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	 {
		 perror("fail to socket");
		 exit(1);

		 }
	 int on=1;

	 if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
	 {
		 perror("fail to setsockopt");
		 exit(1);
		 }
    
	struct sockaddr_in mysockaddr;
	struct sockaddr_in clientaddr;

	mysockaddr.sin_family=AF_INET;
	mysockaddr.sin_port = htons(atoi(argv[2]));
	mysockaddr.sin_addr.s_addr=inet_addr(argv[1]);
	socklen_t socklen = sizeof(mysockaddr);

    socklen_t addrlen = sizeof(clientaddr);

    if(bind(sockfd,(struct sockaddr *)&mysockaddr,socklen)==-1)
	{
		perror("fail to bind");
		exit(1);
		}
	
	 if(listen(sockfd,5)==-1)
	 {
		 perror("fail to listen");
		 exit(1);
		 }
	  int acceptfd;
	 while(1)
	 {
		 if((acceptfd=accept(sockfd,(struct sockaddr *)&clientaddr,&addrlen))==-1)
		 {
			  perror("fail to accept");
			  exit(1);
			   }
		  MSG msg;
		  msg.addr = clientaddr;
          msg.acceptfd=acceptfd; 
		  
          pthread_t thread;

		  if(pthread_create(&thread,NULL,pthread_fun,&msg)!=0)
		{
			perror("fail to pthread_create");
			exit(1);

 			}	  
             pthread_detach(thread);

		  
		 }	
	
	return 0;
	      }

4.3、客户端代码

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>       
#include <sys/socket.h>
#include<string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
 
#define N 128
int main(int argc ,char *argv[])
{
	 if(argc<3)
	 {
		 printf("fail ,lose ip port\n");
		 exit(1);
		 
		 }
	 int sockfd;
 
	 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	 {
		 perror("fail to sockfd");
		 exit(1);
		 
		 }
 
//	  printf("TCP:sockfd= %d\n",sockfd);
        
      struct sockaddr_in mysockaddr;
 
	  mysockaddr.sin_family=AF_INET;
	  mysockaddr.sin_port=htons(atoi(argv[2]));
	  mysockaddr.sin_addr.s_addr=inet_addr(argv[1]);
	  socklen_t addrlen= sizeof(mysockaddr);
 
      if(connect(sockfd,(struct sockaddr*)&mysockaddr,addrlen)==-1)
	  {
		   perror("fail to connect");
		   exit(1);
		   }
	   
	  
	     char buf[N]="";
		 char text[N]="";
	while(1)
	{
		  fgets(buf,N,stdin);
          
		  if(send(sockfd,buf,N,0)==-1)
		  {
			  perror("fail to send");
			  exit(1);
			  
			  }
		  
	     
		 if(recv(sockfd,text,N,0)==-1)
		 {
	          perror("fail to recv");
			  exit(1);
 
			 }
		  
		  printf("from server: %s\n",text);
	    	  
       }    		  
		  close(sockfd);
	  
        	return 0;
	
	}
 

4.4、运行结果

你学会了?? 

 

猜你喜欢

转载自blog.csdn.net/weixin_47783699/article/details/128006471