歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

幾種服務器模型

TCP測試用客戶程序

每次運行客戶程序,在命令行參數指定服務器的ip地址,端口,發起連接的子進程數,和一個待發送的字符串數據,客戶程序將模擬多個客戶根據指定的子進程數創建子進程來並發的連接到服務器,並發送數據,服務器收到數據後都原樣的回發給客戶,是一點典型的回射服務器。

  1. #include "net.h"  
  2.  
  3. char *addr = NULL; 
  4. char *request = NULL; 
  5. unsigned int port; 
  6. int connCount; 
  7. int clientfd; 
  8.  
  9. void client_deal() 
  10. { 
  11.     char *buf = NULL; 
  12.     int len; 
  13.      
  14.     Tcp_connect(addr, port, &clientfd); 
  15.     if (sendAll(clientfd, request, strlen(request)) > 0) 
  16.     { 
  17.         len = recvAll(clientfd, (void**)&buf); 
  18.         if (len > 0) 
  19.         { 
  20.             buf[len] = 0; 
  21.             printf("%s\n", buf); 
  22.         } 
  23.     } 
  24.     freePtr(buf); 
  25.     Close(clientfd); 
  26.     exit(0); 
  27. } 
  28.  
  29. int main(int argc, char **argv) 
  30. { 
  31.     if (argc != 5) 
  32.     { 
  33.         printf("use [ip] [port] [connCount] [request]\n"); 
  34.         exit(-1); 
  35.     } 
  36.      
  37.     addr = argv[1]; 
  38.     port = atoi(argv[2]); 
  39.     connCount = atoi(argv[3]); 
  40.     request = argv[4]; 
  41.      
  42.     for (int i=0; i<connCount; ++i) 
  43.     { 
  44.         if (fork() == 0) 
  45.         { 
  46.             client_deal(); 
  47.         } 
  48.     } 
  49.      
  50.     while (wait(NULL) > 0); 
  51.     if (errno != ECHILD) 
  52.     { 
  53.         perror("wait error"); 
  54.         exit(-1); 
  55.     } 
  56.      
  57.     return 0; 
  58. } 
#include "net.h"

char *addr = NULL;
char *request = NULL;
unsigned int port;
int connCount;
int clientfd;

void client_deal()
{
	char *buf = NULL;
	int len;
	
	Tcp_connect(addr, port, &clientfd);
	if (sendAll(clientfd, request, strlen(request)) > 0)
	{
		len = recvAll(clientfd, (void**)&buf);
		if (len > 0)
		{
			buf[len] = 0;
			printf("%s\n", buf);
		}
	}
	freePtr(buf);
	Close(clientfd);
	exit(0);
}

int main(int argc, char **argv)
{
	if (argc != 5)
	{
		printf("use [ip] [port] [connCount] [request]\n");
		exit(-1);
	}
	
	addr = argv[1];
	port = atoi(argv[2]);
	connCount = atoi(argv[3]);
	request = argv[4];
	
	for (int i=0; i<connCount; ++i)
	{
		if (fork() == 0)
		{
			client_deal();
		}
	}
	
	while (wait(NULL) > 0);
	if (errno != ECHILD)
	{
		perror("wait error");
		exit(-1);
	}
	
	return 0;
}

 

1.迭代服務器

在處理完成某個客戶的請求之後才轉向下一個客戶,比較少見,雖然總的服務時間稍慢,但需要進程控制

  1. #include "net.h"  
  2.  
  3. int listenfd; 
  4.  
  5. void server_deal() 
  6. { 
  7.     char *buf = NULL; 
  8.     ssize_t size; 
  9.     int clifd; 
  10.                      
  11.     Accept(listenfd, NULL, NULL, &clifd); 
  12.     printf("有新連接\n"); 
  13.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  14.         sendAll(clifd, buf, size); 
  15.     freePtr(buf); 
  16.     Close(clifd); 
  17. } 
  18.  
  19. int main() 
  20. { 
  21.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  22.      
  23.     while (1) 
  24.     { 
  25.         server_deal(); 
  26.     } 
  27.      
  28.     return 0; 
  29. } 
#include "net.h"

int listenfd;

void server_deal()
{
	char *buf = NULL;
	ssize_t size;
	int clifd;
					
	Accept(listenfd, NULL, NULL, &clifd);
	printf("有新連接\n");
	if ( (size = recvAll(clifd, (void**)&buf)) > 0)
	    sendAll(clifd, buf, size);
	freePtr(buf);
	Close(clifd);
}

int main()
{
	Tcp_listen("INADDR_ANY", 9999, 5, &listenfd);
	
	while (1)
	{
		server_deal();
	}
	
	return 0;
}

 

2.TCP多進程並發服務器

每個客戶fork出一個子進程並發的去處理請求,總服務器時間稍短,fork子進程比較耗費CPU時間

  1. #include "net.h"  
  2.  
  3. int listenfd; 
  4. int clifd; 
  5.  
  6. void server_deal() 
  7. { 
  8.     char *buf = NULL; 
  9.     ssize_t size; 
  10.                      
  11.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  12.         sendAll(clifd, buf, size); 
  13.     freePtr(buf); 
  14.     Close(clifd); 
  15.     exit(0); 
  16. } 
  17.  
  18. int main() 
  19. { 
  20.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  21.      
  22.     while (1) 
  23.     { 
  24.         Accept(listenfd, NULL, NULL, &clifd); 
  25.         printf("有新連接\n"); 
  26.         if (fork() == 0) 
  27.         { 
  28.             Close(listenfd); 
  29.             server_deal(); 
  30.         } 
  31.         Close(clifd); 
  32.     } 
  33.      
  34.     return 0; 
  35. } 
#include "net.h"

int listenfd;
int clifd;

void server_deal()
{
	char *buf = NULL;
	ssize_t size;
					
	if ( (size = recvAll(clifd, (void**)&buf)) > 0)
	    sendAll(clifd, buf, size);
	freePtr(buf);
	Close(clifd);
	exit(0);
}

int main()
{
	Tcp_listen("INADDR_ANY", 9999, 5, &listenfd);
	
	while (1)
	{
		Accept(listenfd, NULL, NULL, &clifd);
		printf("有新連接\n");
		if (fork() == 0)
		{
			Close(listenfd);
			server_deal();
		}
		Close(clifd);
	}
	
	return 0;
}

 


3.TCP預先派生子進程服務器

與之前的每一個客戶請求臨時fork一個進程處理不同,在啟動的時候就fork出一些子進程,優點是節省了臨時fork的開銷,缺點是父進程在啟動階段要先知道預先派生的子進程數,如果連接較多而無可用子進程,那麼客戶請求超過了連接排隊數就可能會被忽略

  1. #include "net.h"  
  2.  
  3. const int PROCESS_COUNT = 5; 
  4. int listenfd; 
  5.  
  6. void server_deal() 
  7. { 
  8.     int clifd; 
  9.     char *buf = NULL; 
  10.     ssize_t size; 
  11.              
  12.     Accept(listenfd, NULL, NULL, &clifd); 
  13.     printf("子進程%ld有新連接\n", (long)getpid()); 
  14.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  15.         sendAll(clifd, buf, size); 
  16.     freePtr(buf); 
  17.     Close(clifd); 
  18. } 
  19.  
  20. int main() 
  21. { 
  22.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  23.      
  24.     for (int i=0; i<PROCESS_COUNT; ++i) 
  25.     { 
  26.         if (fork() == 0) 
  27.         { 
  28.             while (1) 
  29.             { 
  30.                 server_deal(); 
  31.             } 
  32.         } 
  33.     } 
  34.      
  35.     while (1); 
  36.     return 0; 
  37. } 
#include "net.h"

const int PROCESS_COUNT = 5;
int listenfd;

void server_deal()
{
	int clifd;
	char *buf = NULL;
	ssize_t size;
			
	Accept(listenfd, NULL, NULL, &clifd);
	printf("子進程%ld有新連接\n", (long)getpid());
	if ( (size = recvAll(clifd, (void**)&buf)) > 0)
	    sendAll(clifd, buf, size);
	freePtr(buf);
	Close(clifd);
}

int main()
{
	Tcp_listen("INADDR_ANY", 9999, 5, &listenfd);
	
	for (int i=0; i<PROCESS_COUNT; ++i)
	{
		if (fork() == 0)
		{
			while (1)
			{
				server_deal();
			}
		}
	}
	
	while (1);
	return 0;
}



 

4.TCP預先派生子進程服務器,accept使用文件上鎖保護

因為某些內核實現中不允許多個進程引用對同一個監聽套接字調用accept,所以對accept加鎖成為原子操作為對上一種模型的改進

  1. #include "net.h"  
  2.  
  3. const int PROCESS_COUNT = 5; 
  4. int listenfd; 
  5. int lock_fd; 
  6. struct flock lock_it, unlock_it; 
  7.  
  8. void my_lock_init(const char *pathname) 
  9. { 
  10.     char lock_file[1024]; 
  11.      
  12.     strncpy(lock_file, pathname, sizeof(lock_file)); 
  13.     lock_fd = Mkstemp(lock_file); 
  14.     Unlink(lock_file); 
  15.      
  16.     lock_it.l_type = F_WRLCK; 
  17.     lock_it.l_whence = SEEK_SET; 
  18.     lock_it.l_start = 0; 
  19.     lock_it.l_len = 0; 
  20.      
  21.     unlock_it.l_type = F_UNLCK; 
  22.     unlock_it.l_whence = SEEK_SET; 
  23.     unlock_it.l_start = 0; 
  24.     unlock_it.l_len = 0; 
  25. } 
  26.  
  27. void my_lock_wait() 
  28. { 
  29.     while (fcntl(lock_fd, F_SETLKW, &lock_it) < 0) 
  30.     { 
  31.         if (errno == EINTR) 
  32.             continue; 
  33.         else 
  34.             printErrExit("my_lock_wait error"); 
  35.     } 
  36. } 
  37.  
  38. void my_lock_release() 
  39. { 
  40.     while (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0) 
  41.     { 
  42.         if (errno == EINTR) 
  43.             continue; 
  44.         else 
  45.             printErrExit("my_lock_release error"); 
  46.     } 
  47. } 
  48.  
  49. void server_deal() 
  50. { 
  51.     int clifd; 
  52.     char *buf = NULL; 
  53.     ssize_t size; 
  54.              
  55.     my_lock_wait(); 
  56.     Accept(listenfd, NULL, NULL, &clifd); 
  57.     printf("子進程%ld有新連接\n", (long)getpid()); 
  58.     my_lock_release(); 
  59.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  60.         sendAll(clifd, buf, size); 
  61.     freePtr(buf); 
  62.     Close(clifd); 
  63. } 
  64.  
  65. int main() 
  66. { 
  67.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  68.     my_lock_init("/tmp/lock.XXXXXX"); 
  69.      
  70.     for (int i=0; i<PROCESS_COUNT; ++i) 
  71.     { 
  72.         if (fork() == 0) 
  73.         { 
  74.             while (1) 
  75.             { 
  76.                 server_deal(); 
  77.             } 
  78.         } 
  79.     } 
  80.      
  81.     while (1); 
  82.     return 0; 
  83. } 
#include "net.h"

const int PROCESS_COUNT = 5;
int listenfd;
int lock_fd;
struct flock lock_it, unlock_it;

void my_lock_init(const char *pathname)
{
	char lock_file[1024];
	
	strncpy(lock_file, pathname, sizeof(lock_file));
	lock_fd = Mkstemp(lock_file);
	Unlink(lock_file);
	
	lock_it.l_type = F_WRLCK;
	lock_it.l_whence = SEEK_SET;
	lock_it.l_start = 0;
	lock_it.l_len = 0;
	
	unlock_it.l_type = F_UNLCK;
	unlock_it.l_whence = SEEK_SET;
	unlock_it.l_start = 0;
	unlock_it.l_len = 0;
}

void my_lock_wait()
{
	while (fcntl(lock_fd, F_SETLKW, &lock_it) < 0)
	{
		if (errno == EINTR)
			continue;
		else
			printErrExit("my_lock_wait error");
	}
}

void my_lock_release()
{
	while (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0)
	{
		if (errno == EINTR)
			continue;
		else
			printErrExit("my_lock_release error");
	}
}

void server_deal()
{
	int clifd;
	char *buf = NULL;
	ssize_t size;
			
	my_lock_wait();
	Accept(listenfd, NULL, NULL, &clifd);
	printf("子進程%ld有新連接\n", (long)getpid());
	my_lock_release();
	if ( (size = recvAll(clifd, (void**)&buf)) > 0)
	    sendAll(clifd, buf, size);
	freePtr(buf);
	Close(clifd);
}

int main()
{
	Tcp_listen("INADDR_ANY", 9999, 5, &listenfd);
	my_lock_init("/tmp/lock.XXXXXX");
	
	for (int i=0; i<PROCESS_COUNT; ++i)
	{
		if (fork() == 0)
		{
			while (1)
			{
				server_deal();
			}
		}
	}
	
	while (1);
	return 0;
}



 

5.TCP預先派生子進程服務器,accept使用線程上鎖保護

與上一模型類似,采用多進程間共享線程鎖進行的方式對預先派生進程服務器的改進

  1. #include "net.h"  
  2.  
  3. const int PROCESS_COUNT = 5; 
  4. int listenfd; 
  5. pthread_mutex_t *mptr; 
  6.  
  7. void my_lock_init() 
  8. { 
  9.     int fd; 
  10.      
  11.     pthread_mutexattr_t mattr; 
  12.     fd = Open("/dev/zero", O_RDWR, 0); 
  13.     mptr = (pthread_mutex_t*)Mmap(0, sizeof(pthread_mutex_t),   
  14.             PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
  15.     Close(fd); 
  16.     pthread_mutexattr_init(&mattr); 
  17.     pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); 
  18.     pthread_mutex_init(mptr, &mattr); 
  19. } 
  20.  
  21. void my_lock_wait() 
  22. { 
  23.     pthread_mutex_lock(mptr); 
  24. } 
  25.  
  26. void my_lock_release() 
  27. { 
  28.     pthread_mutex_unlock(mptr); 
  29. } 
  30.  
  31. void server_deal() 
  32. { 
  33.     int clifd; 
  34.     char *buf = NULL; 
  35.     ssize_t size; 
  36.              
  37.     my_lock_wait(); 
  38.     Accept(listenfd, NULL, NULL, &clifd); 
  39.     printf("子進程%ld有新連接\n", (long)getpid()); 
  40.     my_lock_release(); 
  41.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  42.         sendAll(clifd, buf, size); 
  43.     freePtr(buf); 
  44.     Close(clifd); 
  45. } 
  46.  
  47. int main() 
  48. { 
  49.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  50.     my_lock_init(); 
  51.      
  52.     for (int i=0; i<PROCESS_COUNT; ++i) 
  53.     { 
  54.         if (fork() == 0) 
  55.         { 
  56.             while (1) 
  57.             { 
  58.                 server_deal(); 
  59.             } 
  60.         } 
  61.     } 
  62.      
  63.     while (1); 
  64.     return 0; 
  65. } 
#include "net.h"

const int PROCESS_COUNT = 5;
int listenfd;
pthread_mutex_t *mptr;

void my_lock_init()
{
	int fd;
	
	pthread_mutexattr_t mattr;
	fd = Open("/dev/zero", O_RDWR, 0);
	mptr = (pthread_mutex_t*)Mmap(0, sizeof(pthread_mutex_t), 
			PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	Close(fd);
	pthread_mutexattr_init(&mattr);
	pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
	pthread_mutex_init(mptr, &mattr);
}

void my_lock_wait()
{
	pthread_mutex_lock(mptr);
}

void my_lock_release()
{
	pthread_mutex_unlock(mptr);
}

void server_deal()
{
	int clifd;
	char *buf = NULL;
	ssize_t size;
			
	my_lock_wait();
	Accept(listenfd, NULL, NULL, &clifd);
	printf("子進程%ld有新連接\n", (long)getpid());
	my_lock_release();
	if ( (size = recvAll(clifd, (void**)&buf)) > 0)
	    sendAll(clifd, buf, size);
	freePtr(buf);
	Close(clifd);
}

int main()
{
	Tcp_listen("INADDR_ANY", 9999, 5, &listenfd);
	my_lock_init();
	
	for (int i=0; i<PROCESS_COUNT; ++i)
	{
		if (fork() == 0)
		{
			while (1)
			{
				server_deal();
			}
		}
	}
	
	while (1);
	return 0;
}

 

 

6.TCP預先派生子進程服務器,主進程傳遞描述符

主進程中accept後將已連接的套接字通過進程間通信的方式傳遞給預先派生的空閒進程,預先派生的進程處理完成後向主進程發送消息,主進程負責維護所有預先派生進程的狀態以及可用數目

  1. #include "net.h"  
  2.  
  3. #define THREAD_COUNT 5  
  4.  
  5. typedef struct 
  6. { 
  7.     pid_t pid; 
  8.     int   pipefd; 
  9.     int   status; 
  10.     long  count; 
  11. } Child; 
  12.  
  13. int listenfd; 
  14. int navail; 
  15. Child carr[THREAD_COUNT]; 
  16. int tmp_conn_count; 
  17.  
  18. void sig_int(int sig) 
  19. { 
  20.     int i; 
  21.     int sum = 0; 
  22.      
  23.     sum += tmp_conn_count; 
  24.     printf("tmp_conn_count:%d\n", tmp_conn_count); 
  25.     for (i=0; i<THREAD_COUNT; i++) 
  26.     { 
  27.         sum += carr[i].count; 
  28.         printf("carr[%d]'s conn is %ld\n", i, carr[i].count); 
  29.     } 
  30.     printf("sum is %d\n", sum); 
  31.     exit(-1); 
  32. } 
  33.  
  34. void server_deal(int i) 
  35. { 
  36.     int ret; 
  37.     int clifd; 
  38.     char *buf = NULL; 
  39.     char c = 'w'; 
  40.     int size; 
  41.     struct strrecvfd recv_stru; 
  42.      
  43.     while (1) 
  44.     { 
  45.         recvfd(STDERR_FILENO, &clifd); 
  46.         if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  47.             sendAll(clifd, buf, size); 
  48.         Close(clifd); 
  49.         freePtr(buf); 
  50.         buf = NULL; 
  51.         write(STDERR_FILENO, &c, 1);     
  52.     } 
  53. } 
  54.  
  55. void child_make(int i) 
  56. { 
  57.     int sockfd[2]; 
  58.     pid_t pid; 
  59.      
  60.     Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd); 
  61.     //Socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd);  
  62.     if ( (pid = fork()) > 0) 
  63.     { 
  64.         Close(sockfd[1]); 
  65.         carr[i].pipefd = sockfd[0]; 
  66.         carr[i].status = 0; 
  67.         carr[i].count = 0; 
  68.         carr[i].pid = pid; 
  69.     } 
  70.     else 
  71.     { 
  72.         if (dup2(sockfd[1], STDERR_FILENO) < 0) 
  73.             printErrExit("dup2 error"); 
  74.         Close(sockfd[1]); 
  75.         Close(sockfd[0]); 
  76.         Close(listenfd); 
  77.         carr[i].pipefd = sockfd[1]; 
  78.         server_deal(i); 
  79.     } 
  80. } 
  81.  
  82. void temp_child(int clifd) 
  83. { 
  84.     char *buf = NULL; 
  85.     int size; 
  86.      
  87.     if (fork() > 0) 
  88.     { 
  89.         Close(clifd); 
  90.         ++tmp_conn_count; 
  91.     } 
  92.     else 
  93.     { 
  94.         if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  95.             sendAll(clifd, buf, size); 
  96.         Close(clifd); 
  97.         freePtr(buf); 
  98.         exit(0); 
  99.     } 
  100. } 
  101.  
  102. int main() 
  103. { 
  104.     int maxfd; 
  105.     fd_set rset, master; 
  106.     int nsel; 
  107.     int clifd; 
  108.     int i; 
  109.      
  110.     printf("pid:%d\n", getpid()); 
  111.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  112.     FD_ZERO(&rset); 
  113.     FD_SET(listenfd, &master); 
  114.     maxfd = listenfd; 
  115.     tmp_conn_count = 0; 
  116.      
  117.     for (i=0; i<THREAD_COUNT; i++) 
  118.     { 
  119.         child_make(i); 
  120.         FD_SET(carr[i].pipefd, &master); 
  121.         if (maxfd < carr[i].pipefd) 
  122.             maxfd = carr[i].pipefd; 
  123.     } 
  124.      
  125.     navail = THREAD_COUNT; 
  126.     Signal(SIGINT, sig_int); 
  127.     while (1) 
  128.     { 
  129.         printf("navail: %d\n", navail); 
  130.         rset = master; 
  131.         nsel = Select(maxfd+1, &rset, NULL, NULL, NULL); 
  132.         if (FD_ISSET(listenfd, &rset)) 
  133.         { 
  134.             Accept(listenfd, NULL, NULL, &clifd); 
  135.              
  136.             if (navail > 0) 
  137.             { 
  138.                 for (i=0; i<THREAD_COUNT; i++) 
  139.                     if (carr[i].status == 0) 
  140.                         break; 
  141.                  
  142.                 //向子進程傳遞連接上來的套接字描述符  
  143.                 sendfd(carr[i].pipefd, clifd); 
  144.                 carr[i].status = 1; 
  145.                 --navail; 
  146.             } 
  147.             else 
  148.             { 
  149.                 temp_child(clifd);   
  150.             } 
  151.              
  152.             if (--nsel == 0) 
  153.                 continue;         
  154.         } 
  155.          
  156.         for(int i=0; i<THREAD_COUNT; i++) 
  157.         { 
  158.             if (FD_ISSET(carr[i].pipefd, &rset)) 
  159.             { 
  160.                 char c; 
  161.                 read(carr[i].pipefd, &c, sizeof(c)); 
  162.                 carr[i].count++; 
  163.                 carr[i].status = 0; 
  164.                 ++navail; 
  165.                                  
  166.                 if (--nsel == 0) 
  167.                     break;   
  168.             } 
  169.         } 
  170.     } 
  171.          
  172.     return 0; 
  173. } 
#include "net.h"

#define THREAD_COUNT 5

typedef struct
{
	pid_t pid;
	int   pipefd;
	int   status;
	long  count;
} Child;

int listenfd;
int navail;
Child carr[THREAD_COUNT];
int tmp_conn_count;

void sig_int(int sig)
{
	int i;
	int sum = 0;
	
	sum += tmp_conn_count;
	printf("tmp_conn_count:%d\n", tmp_conn_count);
	for (i=0; i<THREAD_COUNT; i++)
	{
		sum += carr[i].count;
		printf("carr[%d]'s conn is %ld\n", i, carr[i].count);
	}
	printf("sum is %d\n", sum);
	exit(-1);
}

void server_deal(int i)
{
	int ret;
	int clifd;
	char *buf = NULL;
	char c = 'w';
	int size;
	struct strrecvfd recv_stru;
	
	while (1)
	{
		recvfd(STDERR_FILENO, &clifd);
		if ( (size = recvAll(clifd, (void**)&buf)) > 0)
	    	sendAll(clifd, buf, size);
	    Close(clifd);
		freePtr(buf);
		buf = NULL;
		write(STDERR_FILENO, &c, 1);	
	}
}

void child_make(int i)
{
	int sockfd[2];
	pid_t pid;
	
	Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
	//Socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd);
	if ( (pid = fork()) > 0)
	{
		Close(sockfd[1]);
		carr[i].pipefd = sockfd[0];
		carr[i].status = 0;
		carr[i].count = 0;
		carr[i].pid = pid;
	}
	else
	{
		if (dup2(sockfd[1], STDERR_FILENO) < 0)
			printErrExit("dup2 error");
		Close(sockfd[1]);
		Close(sockfd[0]);
		Close(listenfd);
		carr[i].pipefd = sockfd[1];
		server_deal(i);
	}
}

void temp_child(int clifd)
{
	char *buf = NULL;
	int size;
	
	if (fork() > 0)
	{
		Close(clifd);
		++tmp_conn_count;
	}
	else
	{
		if ( (size = recvAll(clifd, (void**)&buf)) > 0)
			sendAll(clifd, buf, size);
		Close(clifd);
		freePtr(buf);
		exit(0);
	}
}

int main()
{
	int maxfd;
	fd_set rset, master;
	int nsel;
	int clifd;
	int i;
	
	printf("pid:%d\n", getpid());
	Tcp_listen("INADDR_ANY", 9999, 5, &listenfd);
	FD_ZERO(&rset);
	FD_SET(listenfd, &master);
	maxfd = listenfd;
	tmp_conn_count = 0;
	
	for (i=0; i<THREAD_COUNT; i++)
	{
		child_make(i);
		FD_SET(carr[i].pipefd, &master);
		if (maxfd < carr[i].pipefd)
			maxfd = carr[i].pipefd;
	}
	
	navail = THREAD_COUNT;
	Signal(SIGINT, sig_int);
	while (1)
	{
		printf("navail: %d\n", navail);
		rset = master;
		nsel = Select(maxfd+1, &rset, NULL, NULL, NULL);
		if (FD_ISSET(listenfd, &rset))
		{
			Accept(listenfd, NULL, NULL, &clifd);
			
			if (navail > 0)
			{
				for (i=0; i<THREAD_COUNT; i++)
					if (carr[i].status == 0)
						break;
				
				//向子進程傳遞連接上來的套接字描述符
				sendfd(carr[i].pipefd, clifd);
				carr[i].status = 1;
				--navail;
			}
			else
			{
				temp_child(clifd);	
			}
			
			if (--nsel == 0)
				continue;		
		}
		
		for(int i=0; i<THREAD_COUNT; i++)
		{
			if (FD_ISSET(carr[i].pipefd, &rset))
			{
				char c;
				read(carr[i].pipefd, &c, sizeof(c));
				carr[i].count++;
				carr[i].status = 0;
				++navail;
								
				if (--nsel == 0)
					break;	
			}
		}
	}
		
	return 0;
}

 

客戶程序創建30個子進程連接時,向服務器進程發送SIGINT信號查看各個進程服務數目的分布

     

7.TCP多線程並發服務器

對於每一個客戶請求創建一個線程來處理,與多進程並發服務器相比,創建線程比創建進程的開銷更低

  1. #include "net.h"  
  2.  
  3. int listenfd; 
  4.  
  5. void* server_deal(void *arg) 
  6. { 
  7.     int clifd = *((int*)arg); 
  8.     printf("clifd: %d\n", clifd); 
  9.     char *buf = NULL; 
  10.     ssize_t size; 
  11.                      
  12.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  13.         sendAll(clifd, buf, size); 
  14.     freePtr(buf); 
  15.     freePtr(arg); 
  16.     Close(clifd); 
  17. } 
  18.  
  19. int main() 
  20. { 
  21.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  22.      
  23.     while (1) 
  24.     { 
  25.         int clifd; 
  26.         pthread_t tid; 
  27.         int *arg = NULL; 
  28.          
  29.         Accept(listenfd, NULL, NULL, &clifd); 
  30.         printf("有新連接\n"); 
  31.         arg = (int*)Malloc(sizeof(int)); 
  32.         *arg = clifd; 
  33.         Pthread_create(&tid, NULL, server_deal, arg); 
  34.     } 
  35.      
  36.     return 0; 
  37. } 

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-10/107871p2.htm

Copyright © Linux教程網 All Rights Reserved