(OK) server-client-pthread-c language

server.c

点击(此处)折叠或打开

  1. // gcc -lpthread server.c -o server
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <netinet/in.h>
  7. #include <arpa/inet.h>
  8. #include <sys/socket.h>
  9. #include <pthread.h>


  10. //#endif
  11. #define BUF_SIZE 1024        //默认缓冲区
  12. #define SERVER_PORT 11111    //监听端口
  13. #define SERVER_HOST "127.0.0.1"    //服务器IP地址
  14. #define EPOLL_RUN_TIMEOUT -1    //epoll的超时时间
  15. #define EPOLL_SIZE 10000    //epoll监听的客户端的最大数目
  16. #define LISTEN_SIZE 10        //监听队列长度

  17. #define STR_WELCOME "Welcome to seChat! You ID is : Client #%d"
  18. #define STR_MESSAGE "Client #%d>> %s"
  19. #define STR_NOONE_CONNECTED "Noone connected to server expect you!"
  20. #define CMD_EXIT "EXIT"

  21. //两个有用的宏定义:检查和赋值并且检测
  22. #define CHK(eval) if(eval < 0){perror("eval"); exit(-1);}
  23. #define CHK2(res, eval) if((res = eval) < 0){perror("eval"); exit(-1);}

  24. void* handle_message(void *arg);

  25. int main(int argc, char *argv[])
  26. {
  27.     int listener;        //监听socket
  28.     struct sockaddr_in addr, peer;
  29.     addr.sin_family = PF_INET;
  30.     addr.sin_port = htons(SERVER_PORT);
  31.     addr.sin_addr.s_addr = inet_addr(SERVER_HOST);
  32.     socklen_t socklen;
  33.     socklen = sizeof(struct sockaddr_in);

  34.     int client;

  35.     CHK2(listener, socket(PF_INET, SOCK_STREAM, 0));    //初始化监听socket

  36.     // 设置套接字选项避免地址使用错误
  37.     int on=1;
  38.     if((setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
  39.     {
  40.         perror("setsockopt failed");
  41.         exit(EXIT_FAILURE);
  42.     }

  43.     CHK(bind(listener, (struct sockaddr *)&addr, sizeof(addr)));    //绑定监听socket

  44.     //printf("listen ");
  45.     CHK(listen(listener, LISTEN_SIZE));    //设置监听
  46.     printf("listening ");

  47.     while (1) {
  48.         //printf("accept ");
  49.         CHK2(client, accept(listener, (struct sockaddr *)&peer, &socklen));
  50.         printf("accepted ");

  51.         pthread_t reader;
  52.         int rt = pthread_create(&reader, NULL, handle_message, (void *)&client);
  53.         if (-1 == rt) {
  54.             printf("thread creation error ");
  55.             return -1;
  56.         }
  57.     }
  58. }

  59. void* handle_message(void *arg)
  60. {
  61.     int client = *((int*)arg);
  62.     //sleep(5);
  63.     char buf[BUF_SIZE];
  64.     int len;

  65.     while(1){
  66.         bzero(buf, BUF_SIZE);
  67.         CHK2(len, recv(client, buf, BUF_SIZE, 0));    //接受客户端信息
  68.         if (len == 0)        //客户端关闭或出错,关闭socket,并从list移除socket
  69.         {
  70.             printf("close-client: %d ", client);
  71.             CHK(close(client));
  72.             return NULL;
  73.         } else            //向客户端发送信息
  74.         {
  75.             CHK(send(client, STR_NOONE_CONNECTED, strlen(STR_NOONE_CONNECTED), 0));
  76.             printf("receive: %s from %d ", buf, client);
  77.         }
  78.     }
  79.     //return len;
  80.     //return NULL;
  81. }
client.c

点击(此处)折叠或打开

  1. // gcc client.c -o client
  2. // gcc -lpthread client.c -o client
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <sys/socket.h>
  10. #include <sys/epoll.h>

  11. //#endif
  12. #define BUF_SIZE 1024        //默认缓冲区
  13. #define SERVER_PORT 11111    //监听端口
  14. #define SERVER_HOST "127.0.0.1"    //服务器IP地址
  15. #define EPOLL_RUN_TIMEOUT -1    //epoll的超时时间
  16. #define EPOLL_SIZE 10000    //epoll监听的客户端的最大数目

  17. #define STR_WELCOME "Welcome to seChat! You ID is : Client #%d"
  18. #define STR_MESSAGE "Client #%d>> %s"
  19. #define STR_NOONE_CONNECTED "Noone connected to server expect you!"
  20. #define CMD_EXIT "EXIT"

  21. //两个有用的宏定义:检查和赋值并且检测
  22. #define CHK(eval) if(eval < 0){perror("eval"); exit(-1);}
  23. #define CHK2(res, eval) if((res = eval) < 0){perror("eval"); exit(-1);}

  24. char message[BUF_SIZE];

  25. /*
  26.     流程:
  27.         调用fork产生两个进程,两个进程通过管道进行通信
  28.         子进程:等待客户输入,并将客户输入的信息通过管道写给父进程
  29.         父进程:接受服务器的信息并显示,将从子进程接受到的信息发送给服务器
  30. */
  31. int main(int argc, char *argv[])
  32. {
  33.     int sock, pid, pipe_fd[2], epfd;

  34.     struct sockaddr_in addr;
  35.     addr.sin_family = PF_INET;
  36.     addr.sin_port = htons(SERVER_PORT);
  37.     addr.sin_addr.s_addr = inet_addr(SERVER_HOST);

  38.     static struct epoll_event ev, events[2];
  39.     ev.events = EPOLLIN | EPOLLET;

  40.     //退出标志
  41.     int continue_to_work = 1;

  42.     CHK2(sock, socket(PF_INET, SOCK_STREAM, 0));
  43.     CHK(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0);

  44.     CHK(pipe(pipe_fd));

  45.     CHK2(epfd, epoll_create(EPOLL_SIZE));

  46.     ev.data.fd = sock;
  47.     CHK(epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev));

  48.     ev.data.fd = pipe_fd[0];
  49.     CHK(epoll_ctl(epfd, EPOLL_CTL_ADD, pipe_fd[0], &ev));

  50.     // 调用fork产生两个进程
  51.     CHK2(pid, fork());
  52.     switch (pid) {
  53.     case 0:        // 子进程
  54.         close(pipe_fd[0]);    // 关闭读端
  55.         printf("Enter 'exit' to exit ");
  56.         while (continue_to_work) {
  57.             bzero(&message, BUF_SIZE);
  58.             fgets(message, BUF_SIZE, stdin);

  59.             // 当收到exit命令时,退出
  60.             if (strncasecmp(message, CMD_EXIT, strlen(CMD_EXIT)) == 0) {
  61.                 continue_to_work = 0;
  62.             } else {
  63.                 CHK(write(pipe_fd[1], message, strlen(message) - 1));
  64.             }
  65.         }
  66.         break;
  67.     default:        // 父进程
  68.         close(pipe_fd[1]);    // 关闭写端
  69.         int epoll_events_count, res;
  70.         while (continue_to_work) {
  71.             CHK2(epoll_events_count, epoll_wait(epfd, events, 2, EPOLL_RUN_TIMEOUT));

  72.             for (int i = 0; i < epoll_events_count; i++) {
  73.                 bzero(&message, BUF_SIZE);
  74.                 if (events[i].data.fd == sock)    //从服务器接受信息
  75.                 {
  76.                     CHK2(res, recv(sock, message, BUF_SIZE, 0));
  77.                     if (res == 0)    //服务器已关闭
  78.                     {
  79.                         CHK(close(sock));
  80.                         continue_to_work = 0;
  81.                     } else {
  82.                         printf("%s ", message);
  83.                     }
  84.                 } else    //从子进程接受信息
  85.                 {
  86.                     CHK2(res, read(events[i].data.fd, message, BUF_SIZE));
  87.                     if (res == 0) {
  88.                         continue_to_work = 0;
  89.                     } else {
  90.                         CHK(send(sock, message, BUF_SIZE, 0));
  91.                     }
  92.                 }
  93.             }
  94.         }
  95.     }
  96.     if (pid) {
  97.         close(pipe_fd[0]);
  98.         close(sock);
  99.     } else {
  100.         close(pipe_fd[1]);
  101.     }

  102.     return 0;
  103. }




原文地址:https://www.cnblogs.com/ztguang/p/12647123.html