Linux服务器开发的几种模型

来源:互联网 发布:ubuntu改ip 编辑:程序博客网 时间:2024/06/01 13:13

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

 

1.迭代服务器

在处理完成某个客户的请求之后才转向下一个客户,比较少见,虽然总的服务时间稍慢,但需要进程控制

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

 

2.TCP多进程并发服务器

每个客户fork出一个子进程并发的去处理请求,总服务器时间稍短,fork子进程比较耗费CPU时间

  1. #include "net.h"  
  2.  
  3. int listenfd; 
  4. int clifd; 
  5.  
  6. void server_deal() 
  7.     char *buf = NULL; 
  8.     ssize_t size; 
  9.                      
  10.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  11.         sendAll(clifd, buf, size); 
  12.     freePtr(buf); 
  13.     Close(clifd); 
  14.     exit(0); 
  15.  
  16. int main() 
  17.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  18.      
  19.     while (1) 
  20.     { 
  21.         Accept(listenfd, NULL, NULL, &clifd); 
  22.         printf("有新连接\n"); 
  23.         if (fork() == 0) 
  24.         { 
  25.             Close(listenfd); 
  26.             server_deal(); 
  27.         } 
  28.         Close(clifd); 
  29.     } 
  30.      
  31.     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.     int clifd; 
  8.     char *buf = NULL; 
  9.     ssize_t size; 
  10.              
  11.     Accept(listenfd, NULL, NULL, &clifd); 
  12.     printf("子进程%ld有新连接\n", (long)getpid()); 
  13.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  14.         sendAll(clifd, buf, size); 
  15.     freePtr(buf); 
  16.     Close(clifd); 
  17.  
  18. int main() 
  19.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  20.      
  21.     for (int i=0; i<PROCESS_COUNT; ++i) 
  22.     { 
  23.         if (fork() == 0) 
  24.         { 
  25.             while (1) 
  26.             { 
  27.                 server_deal(); 
  28.             } 
  29.         } 
  30.     } 
  31.      
  32.     while (1); 
  33.     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.     char lock_file[1024]; 
  10.      
  11.     strncpy(lock_file, pathname, sizeof(lock_file)); 
  12.     lock_fd = Mkstemp(lock_file); 
  13.     Unlink(lock_file); 
  14.      
  15.     lock_it.l_type = F_WRLCK; 
  16.     lock_it.l_whence = SEEK_SET; 
  17.     lock_it.l_start = 0; 
  18.     lock_it.l_len = 0; 
  19.      
  20.     unlock_it.l_type = F_UNLCK; 
  21.     unlock_it.l_whence = SEEK_SET; 
  22.     unlock_it.l_start = 0; 
  23.     unlock_it.l_len = 0; 
  24.  
  25. void my_lock_wait() 
  26.     while (fcntl(lock_fd, F_SETLKW, &lock_it) < 0) 
  27.     { 
  28.         if (errno == EINTR) 
  29.             continue
  30.         else 
  31.             printErrExit("my_lock_wait error"); 
  32.     } 
  33.  
  34. void my_lock_release() 
  35.     while (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0) 
  36.     { 
  37.         if (errno == EINTR) 
  38.             continue
  39.         else 
  40.             printErrExit("my_lock_release error"); 
  41.     } 
  42.  
  43. void server_deal() 
  44.     int clifd; 
  45.     char *buf = NULL; 
  46.     ssize_t size; 
  47.              
  48.     my_lock_wait(); 
  49.     Accept(listenfd, NULL, NULL, &clifd); 
  50.     printf("子进程%ld有新连接\n", (long)getpid()); 
  51.     my_lock_release(); 
  52.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  53.         sendAll(clifd, buf, size); 
  54.     freePtr(buf); 
  55.     Close(clifd); 
  56.  
  57. int main() 
  58.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  59.     my_lock_init("/tmp/lock.XXXXXX"); 
  60.      
  61.     for (int i=0; i<PROCESS_COUNT; ++i) 
  62.     { 
  63.         if (fork() == 0) 
  64.         { 
  65.             while (1) 
  66.             { 
  67.                 server_deal(); 
  68.             } 
  69.         } 
  70.     } 
  71.      
  72.     while (1); 
  73.     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.     int fd; 
  9.      
  10.     pthread_mutexattr_t mattr; 
  11.     fd = Open("/dev/zero", O_RDWR, 0); 
  12.     mptr = (pthread_mutex_t*)Mmap(0, sizeof(pthread_mutex_t),   
  13.             PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
  14.     Close(fd); 
  15.     pthread_mutexattr_init(&mattr); 
  16.     pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); 
  17.     pthread_mutex_init(mptr, &mattr); 
  18.  
  19. void my_lock_wait() 
  20.     pthread_mutex_lock(mptr); 
  21.  
  22. void my_lock_release() 
  23.     pthread_mutex_unlock(mptr); 
  24.  
  25. void server_deal() 
  26.     int clifd; 
  27.     char *buf = NULL; 
  28.     ssize_t size; 
  29.              
  30.     my_lock_wait(); 
  31.     Accept(listenfd, NULL, NULL, &clifd); 
  32.     printf("子进程%ld有新连接\n", (long)getpid()); 
  33.     my_lock_release(); 
  34.     if ( (size = recvAll(clifd, (void**)&buf)) > 0) 
  35.         sendAll(clifd, buf, size); 
  36.     freePtr(buf); 
  37.     Close(clifd); 
  38.  
  39. int main() 
  40.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  41.     my_lock_init(); 
  42.      
  43.     for (int i=0; i<PROCESS_COUNT; ++i) 
  44.     { 
  45.         if (fork() == 0) 
  46.         { 
  47.             while (1) 
  48.             { 
  49.                 server_deal(); 
  50.             } 
  51.         } 
  52.     } 
  53.      
  54.     while (1); 
  55.     return 0; 

 

 

6.TCP预先派生子进程服务器,主进程传递描述符

主进程中accept后将已连接的套接字通过进程间通信的方式传递给预先派生的空闲进程,预先派生的进程处理完成后向主进程发送消息,主进程负责维护所有预先派生进程的状态以及可用数目

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

 

客户程序创建30个子进程连接时,向服务器进程发送SIGINT信号查看各个进程服务数目的分布

 
 
 

7.TCP多线程并发服务器

对于每一个客户请求创建一个线程来处理,与多进程并发服务器相比,创建线程比创建进程的开销更低

  1. #include "net.h"  
  2.  
  3. int listenfd; 
  4.  
  5. void* server_deal(void *arg) 
  6.     int clifd = *((int*)arg); 
  7.     printf("clifd: %d\n", clifd); 
  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.     freePtr(arg); 
  15.     Close(clifd); 
  16.  
  17. int main() 
  18.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  19.      
  20.     while (1) 
  21.     { 
  22.         int clifd; 
  23.         pthread_t tid; 
  24.         int *arg = NULL; 
  25.          
  26.         Accept(listenfd, NULL, NULL, &clifd); 
  27.         printf("有新连接\n"); 
  28.         arg = (int*)Malloc(sizeof(int)); 
  29.         *arg = clifd; 
  30.         Pthread_create(&tid, NULL, server_deal, arg); 
  31.     } 
  32.      
  33.     return 0; 

8.TCP预先创建线程服务器,每个线程各自accept

  1. #include "net.h"  
  2.  
  3. #define THREAD_COUNT 5  
  4. int listenfd; 
  5. pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; 
  6.  
  7. void server_deal() 
  8.     int clifd; 
  9.     int len; 
  10.     char *buf = NULL; 
  11.  
  12.     pthread_mutex_lock(&mylock);     
  13.     Accept(listenfd, NULL, NULL, &clifd); 
  14.     pthread_mutex_unlock(&mylock); 
  15.     if ( (len = recvAll(clifd, (void**)&buf)) > 0) 
  16.         sendAll(clifd, buf, len); 
  17.     Close(clifd); 
  18.  
  19. void* handler(void *arg) 
  20.     while (1) 
  21.     { 
  22.         server_deal(); 
  23.     } 
  24.  
  25. int main() 
  26.     pthread_t tid; 
  27.      
  28.     Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); 
  29.      
  30.     for (int i=0; i<THREAD_COUNT; ++i) 
  31.         Pthread_create(&tid, NULL, handler, NULL); 
  32.          
  33.     while (1);   
  34.     return 0; 



 

net.h头文件

  1. #ifndef MY_NET_H   
  2. #define MY_NET_H   
  3.        
  4. #include <sys/types.h>         
  5. #include <sys/socket.h>   
  6. #include <stdio.h>   
  7. #include <stdlib.h>   
  8. #include <arpa/inet.h>   
  9. #include <unistd.h>   
  10. #include <time.h>   
  11. #include <string.h>   
  12. #include <sys/select.h>   
  13. #include <sys/time.h>   
  14. #include <errno.h>  
  15. #include <signal.h>  
  16. #include <sys/wait.h>  
  17. #include <pthread.h>  
  18. #include <fcntl.h>  
  19. #include <sys/mman.h>  
  20. #include <sys/ioctl.h>  
  21. #include <stropts.h>  
  22.        
  23. #define MAXLINE 4096   
  24. #define SA struct sockaddr   
  25. #define LISTENEQ 10  
  26.  
  27. //清除数据  
  28. //ptr 指针  
  29. void freePtr(void *ptr) 
  30.     if (ptr != NULL) 
  31.         free(ptr); 
  32.  
  33. //打印错误信息并终止进程  
  34. //errStr 错误字符串  
  35. void printErrExit(const char* errStr) 
  36.     if (errStr != NULL) 
  37.         perror(errStr); 
  38.     printf("进程pid:%d\n", getpid()); 
  39.     exit(-1); 
  40.  
  41. int Open(const char *pathname, int flags, mode_t mode) 
  42.     int fd; 
  43.      
  44.     while ( (fd = open(pathname, flags, mode)) < 0) 
  45.     { 
  46.         if (errno == EINTR) 
  47.             continue
  48.         printErrExit("Open error"); 
  49.     } 
  50.      
  51.     return fd; 
  52.  
  53. int Socketpair(int domain, int type, int protocol, int sv[2]) 
  54.     if (socketpair(domain, type, protocol, sv) < 0) 
  55.         printErrExit("Socketpair error"); 
  56.  
  57. void Signal(int signum, sighandler_t handler) 
  58.     if (signal(signum, handler) == SIG_ERR) 
  59.         printErrExit("Signal error"); 
  60.  
  61. int Select(int nfds, fd_set *readfds, fd_set *writefds, 
  62.            fd_set *exceptfds, struct timeval *timeout) 
  63.     int ret; 
  64.      
  65.     while ( (ret = select(nfds, readfds, writefds, exceptfds, timeout)) < 0) 
  66.     { 
  67.         if (errno == EINTR) 
  68.             continue;   
  69.         printErrExit("Select error"); 
  70.     } 
  71.      
  72.     return ret; 
  73.                  
  74. ssize_t Read(int fd, void *buf, size_t count) 
  75.     int ret; 
  76.      
  77.     while ( (ret = read(fd, buf, count)) < 0) 
  78.     { 
  79.         if (errno == EINTR) 
  80.             continue
  81.         printErrExit("Read error"); 
  82.     } 
  83.      
  84.     return ret; 
  85.  
  86. ssize_t Write(int fd, const void *buf, size_t count) 
  87.     int ret; 
  88.      
  89.     while ( (ret = write(fd, buf, count)) < 0) 
  90.     { 
  91.         if (errno == EINTR) 
  92.             continue
  93.         printErrExit("Write error"); 
  94.     } 
  95.      
  96.     return ret; 
  97.  
  98. void Dup2(int oldfd, int newfd) 
  99.     while (dup2(oldfd, newfd) < 0) 
  100.     { 
  101.         if (errno == EINTR) 
  102.             continue
  103.         printErrExit("Dup2 error"); 
  104.     } 
  105.  
  106. void *Mmap(void *addr, size_t length, int prot, 
  107.            int flags, int fd, off_t offset) 
  108.     void *ptr; 
  109.      
  110.     if ( (ptr = mmap(addr, length, prot, flags, 
  111.           fd, offset)) == MAP_FAILED) 
  112.         printErrExit("Mmap error"); 
  113.      
  114.     return ptr; 
  115.  
  116. int Mkstemp(char *path) 
  117.     int lock_fd; 
  118.      
  119.     if ( (lock_fd = mkstemp(path)) < 0) 
  120.         printErrExit("Mkstemp error"); 
  121.      
  122.     return lock_fd; 
  123.  
  124. void Unlink(const char *pathname) 
  125.     if (unlink(pathname) < 0) 
  126.         printErrExit("Unlink error"); 
  127.  
  128.  
  129. void* Malloc(size_t size) 
  130.     void *ret = NULL; 
  131.      
  132.     if ( (ret = malloc(size)) == NULL) 
  133.         printErrExit("Malloc error"); 
  134.      
  135.     return ret;       
  136. }   
  137.  
  138. int sendfd(int fd, int fd_to_send) 
  139.     struct iovec iov; 
  140.     struct msghdr msg; 
  141.     struct cmsghdr *cmsg; 
  142.     char   buf = ' '
  143.      
  144.     iov.iov_base = &buf; 
  145.     iov.iov_len = 1; 
  146.      
  147.     cmsg = (struct cmsghdr*)malloc(CMSG_LEN(sizeof(int))); 
  148.     cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 
  149.     cmsg->cmsg_level = SOL_SOCKET; 
  150.     cmsg->cmsg_type = SCM_RIGHTS; 
  151.     *(int*)CMSG_DATA(cmsg) = fd_to_send;   
  152.      
  153.     msg.msg_name = NULL; 
  154.     msg.msg_namelen = 0; 
  155.     msg.msg_iov = &iov; 
  156.     msg.msg_iovlen = 1; 
  157.     msg.msg_control = cmsg; 
  158.     msg.msg_controllen = CMSG_LEN(sizeof(int)); 
  159.     msg.msg_flags = 0; 
  160.      
  161.     while (sendmsg(fd, &msg, 0) < 0) 
  162.     { 
  163.         if (errno == EINTR) 
  164.             continue
  165.              
  166.         return -1; 
  167.     } 
  168.      
  169.     return 0; 
  170.  
  171. int recvfd(int fd, int *fd_to_recv) 
  172.     struct iovec iov; 
  173.     struct msghdr msg; 
  174.     struct cmsghdr *cmsg; 
  175.     char   buf; 
  176.     int ret; 
  177.      
  178.     iov.iov_base = &buf; 
  179.     iov.iov_len = 1; 
  180.      
  181.     cmsg = (struct cmsghdr*)malloc(CMSG_LEN(sizeof(int))); 
  182.     cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 
  183.     cmsg->cmsg_level = SOL_SOCKET; 
  184.     cmsg->cmsg_type = SCM_RIGHTS; 
  185.      
  186.     msg.msg_name = NULL; 
  187.     msg.msg_namelen = 0; 
  188.     msg.msg_iov = &iov; 
  189.     msg.msg_iovlen = 1; 
  190.     msg.msg_control = cmsg; 
  191.     msg.msg_controllen = CMSG_LEN(sizeof(int)); 
  192.     msg.msg_flags = 0; 
  193.      
  194.     while ( (ret = recvmsg(fd, &msg, 0)) < 0) 
  195.     { 
  196.         if (errno == EINTR) 
  197.             continue
  198.              
  199.         return -1; 
  200.     } 
  201.          
  202.     if (ret == 0) 
  203.         return 0; 
  204.      
  205.     *fd_to_recv = *(int*)CMSG_DATA((struct cmsghdr*)msg.msg_control); 
  206.     return *fd_to_recv; 
  207.  
  208. //执行close  
  209. //fd 描述符  
  210. void Close(int fd) 
  211.     while (close(fd) < 0) 
  212.     { 
  213.         if (errno == EINTR) 
  214.             continue
  215.         printErrExit("Close error"); 
  216.     } 
  217.  
  218.  
  219. //执行accept  
  220. //skfd 描述符  
  221. //addr struct sockaddr结构  
  222. //addrlen addr的大小  
  223. //ret 返回值  
  224. void Accept(int skfd, SA *addr, socklen_t *addrlen, int *ret) 
  225.     int clifd; 
  226.      
  227.     if (ret == NULL) 
  228.         printErrExit("Accept error"); 
  229.      
  230.     while ((clifd = accept(skfd, addr, addrlen)) < 0) 
  231.     { 
  232.         if (errno == EINTR) 
  233.             continue
  234.         printErrExit("Accept error");         
  235.     } 
  236.      
  237.     *ret = clifd; 
  238.  
  239. //初始化struct sockaddr_in结构  
  240. //stru 指向要初始化的struct sockaddr_in结构的指针  
  241. //protoc 地址族  
  242. //addr   ip地址,可以是INADDR_ANY  
  243. //port   端口  
  244. //返回值:成功返回0,出错返回-1  
  245. //注意:不对protoc(地址族)参数进行检查  
  246. int init_sockaddr(struct sockaddr_in *stru, int protoc, const char *addr, unsigned int port) 
  247.     if (stru == NULL || addr == NULL) 
  248.         return -1;   
  249.      
  250.     if (port > 65535) 
  251.         return -1; 
  252.      
  253.     memset(stru, 0, sizeof(struct sockaddr_in)); 
  254.      
  255.     if (strcmp(addr, "INADDR_ANY") == 0) 
  256.         (stru->sin_addr).s_addr = htonl(INADDR_ANY); 
  257.     else 
  258.     { 
  259.         if (inet_addr(addr) == INADDR_NONE) 
  260.             return -1; 
  261.         (stru->sin_addr).s_addr = inet_addr(addr); 
  262.      
  263.     } 
  264.      
  265.     stru->sin_family = protoc; 
  266.     stru->sin_port = htons(port); 
  267.     return 0; 
  268.  
  269. void Init_sockaddr(struct sockaddr_in *stru, int protoc, const char *addr, unsigned int port) 
  270.     if (stru == NULL || addr == NULL) 
  271.         printErrExit("Init_sockaddr error"); 
  272.          
  273.     if (port > 65535) 
  274.         printErrExit("Init_sockaddr error"); 
  275.      
  276.     memset(stru, 0, sizeof(struct sockaddr_in)); 
  277.      
  278.     if (strcmp(addr, "INADDR_ANY") == 0) 
  279.         (stru->sin_addr).s_addr = htonl(INADDR_ANY); 
  280.     else 
  281.     { 
  282.         if (inet_addr(addr) == INADDR_NONE) 
  283.             printErrExit("Init_sockaddr error"); 
  284.          
  285.         (stru->sin_addr).s_addr = inet_addr(addr); 
  286.     } 
  287.      
  288.     stru->sin_family = protoc; 
  289.     stru->sin_port = htons(port); 
  290.  
  291. //建立一个TCP套接字并连接到指定ip地址和指定端口(阻塞版本,connect会一直阻塞,直到到达默认超时时间)  
  292. //addr ip地址  
  293. //port 端口  
  294. //返回值:连接成功返回描述符,出错返回-1  
  295. int tcp_connect(const char *addr, unsigned int port) 
  296. {     
  297.     int skfd; 
  298.     struct sockaddr_in saddr; 
  299.      
  300.     if( (init_sockaddr(&saddr, AF_INET, addr, port)) < 0) 
  301.         return -1; 
  302.          
  303.     if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
  304.         return -1; 
  305.      
  306.     while (connect(skfd, (SA*)&saddr, sizeof(saddr)) < 0) 
  307.     { 
  308.         if (errno == EINTR) 
  309.             continue
  310.         else 
  311.         { 
  312.             close(skfd); 
  313.             return -1; 
  314.         } 
  315.     } 
  316.          
  317.     return skfd; 
  318.  
  319. void Tcp_connect(const char *addr, unsigned int port, int *ret) 
  320. {     
  321.     int skfd; 
  322.     struct sockaddr_in saddr; 
  323.      
  324.     if (ret == NULL) 
  325.         printErrExit("Tcp_connect error"); 
  326.      
  327.     if (init_sockaddr(&saddr, AF_INET, addr, port) < 0) 
  328.         printErrExit("Tcp_connect error"); 
  329.      
  330.     if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
  331.         printErrExit("Tcp_connect error"); 
  332.      
  333.     while (connect(skfd, (SA*)&saddr, sizeof(saddr)) < 0) 
  334.     { 
  335.         if (errno == EINTR) 
  336.             continue
  337.         else 
  338.         { 
  339.             close(skfd); 
  340.             printErrExit("Tcp_connect error"); 
  341.         } 
  342.     } 
  343.          
  344.     *ret = skfd; 
  345.  
  346.  
  347. //建立一个���接字,并且绑定,监听  
  348. //addr 要绑定的ip地址 INADDR_ANY或ipv4地址  
  349. //port 要监听的端口  
  350. //backlog listen函数的监听排队数  
  351. //返回值:成功返回套接字描述符,出错返回-1  
  352. int tcp_listen(const char *addr, unsigned int port, int backlog) 
  353.     int skfd; 
  354.     struct sockaddr_in saddr; 
  355.      
  356.     if (init_sockaddr(&saddr, AF_INET, addr, port) < 0) 
  357.         return -1; 
  358.      
  359.     if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
  360.         return -1; 
  361.      
  362.     if (bind(skfd, (SA*)&saddr, sizeof(saddr)) < 0) 
  363.     { 
  364.         close(skfd); 
  365.         return -1; 
  366.     } 
  367.      
  368.     if (listen(skfd, backlog) < 0) 
  369.     { 
  370.         close(skfd); 
  371.         return -1; 
  372.     } 
  373.      
  374.     return skfd; 
  375.  
  376. void Tcp_listen(const char *addr, unsigned int port, int backlog, int *ret) 
  377.     int skfd; 
  378.     struct sockaddr_in saddr; 
  379.      
  380.     if (ret == NULL) 
  381.         printErrExit("Tcp_listen error"); 
  382.      
  383.     if (init_sockaddr(&saddr, AF_INET, addr, port) < 0) 
  384.         printErrExit("Tcp_listen error"); 
  385.      
  386.     if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
  387.         printErrExit("Tcp_listen error"); 
  388.      
  389.     if (bind(skfd, (SA*)&saddr, sizeof(saddr)) < 0) 
  390.     { 
  391.         close(skfd); 
  392.         printErrExit("Tcp_listen error"); 
  393.     } 
  394.      
  395.     if (listen(skfd, backlog) < 0) 
  396.     { 
  397.         close(skfd); 
  398.         printErrExit("Tcp_listen error"); 
  399.     } 
  400.      
  401.     *ret = skfd; 
  402.  
  403. //发送n个字节  
  404. //fd 描述符  
  405. //vptr指向要发送的数据  
  406. //n 要发送的字节数  
  407. //出错返回-1,否则返回发送的字节数  
  408. ssize_t writen(int fd, const void *vptr, size_t n) 
  409.     size_t nleft = n; 
  410.     ssize_t nwritten; 
  411.     const char *ptr = (const char*)vptr; 
  412.      
  413.     while (nleft > 0) 
  414.     { 
  415.         if ( (nwritten = write(fd, ptr, nleft)) <= 0 ) 
  416.         { 
  417.             if (nwritten < 0 && errno == EINTR) 
  418.                 nwritten = 0; 
  419.             else 
  420.                 return (-1); 
  421.         } 
  422.          
  423.         nleft -= nwritten; 
  424.         ptr += nwritten; 
  425.     } 
  426.      
  427.     return (n); 
  428.  
  429. //读取指定的字节数  
  430. //fd 描述符  
  431. //ptr 指向存放数据的指针  
  432. //n 要接收的字节数  
  433. //对端关闭返回0,出错返回-1,否则返回接收的字节数  
  434. ssize_t readn(int fd, void *vptr, size_t n) 
  435.     char c; 
  436.     int ret; 
  437.     char *ptr = (char*)vptr; 
  438.     size_t i; 
  439.     ssize_t size = 0; 
  440.          
  441.     if (vptr == NULL) 
  442.         return -1; 
  443.  
  444.     for(i=0; i<n; i++) 
  445.     { 
  446.         ret = read(fd, &c, 1); 
  447.          
  448.         if (ret == 0) 
  449.             return 0; 
  450.         else if (ret < 0 && errno == EINTR) 
  451.             i--; 
  452.         else if (ret == 1) 
  453.             ptr[i] = c; 
  454.         else 
  455.             return -1; 
  456.     } 
  457.      
  458.     return n; 
  459.  
  460.  
  461. //发送指定的字节数的数据  
  462. //skfd 套接字描述符  
  463. //sendbuf 要发送的字符串  
  464. //size 要发送的字节数  
  465. //出错返回-1,否则返回发送的字节数  
  466. ssize_t sendAll(int skfd, const void* sendBuf, size_t size) 
  467.     const char *ptr = (const char*)sendBuf; 
  468.      
  469.     if (sendBuf == NULL) 
  470.         return -1; 
  471.      
  472.     if (writen(skfd, &size, sizeof(size)) == sizeof(size)) 
  473.     { 
  474.         if (writen(skfd, ptr, size) == size) 
  475.             return size; 
  476.         else 
  477.             return -1; 
  478.     } 
  479.      
  480.     return -1; 
  481.  
  482. //接收指定字节数的数据  
  483. //skfd 描述符  
  484. //recvbuf 存放接收数据  
  485. //size 要接收的数据大小  
  486. //返回接收的字节数  
  487. //出错返回-1, 对端关闭返回0, 否则返回接收的字节数  
  488. ssize_t recvAll(int skfd, void **recvPtr) 
  489.     size_t len; 
  490.     ssize_t ret;   
  491.      
  492.     ret = readn(skfd, &len, sizeof(len)); 
  493.     if (ret == 0) 
  494.         return 0; 
  495.     if (ret < 0) 
  496.         return -1; 
  497.      
  498.     freePtr(*recvPtr); 
  499.     *recvPtr = Malloc(len + 1); 
  500.     ret = readn(skfd, *recvPtr, len); 
  501.     if (ret == 0) 
  502.     { 
  503.         freePtr(*recvPtr); 
  504.         return 0; 
  505.     } 
  506.     if (ret < 0) 
  507.     { 
  508.         freePtr(*recvPtr); 
  509.         return -1; 
  510.     } 
  511.      
  512.     return ret; 
  513.  
  514. void Pthread_create(pthread_t *threadconst pthread_attr_t *attr, 
  515.                     void *(*start_routine) (void *), void *arg) 
  516.     if (pthread_create(thread, attr, start_routine, arg) != 0) 
  517.         printErrExit("Pthread_create error"); 
  518.  
  519. #endif  
0 0