zoukankan      html  css  js  c++  java
  • (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. }




  • 相关阅读:
    临时生成的文件下载“提速” (提早开始下载)(node.js)
    node.js http接口调试时请求串行特性分析
    presto 判断数据量是否大于一个比较小的值的优化
    typescript 关于class属性类型定义被属性默认值覆盖的问题及解决方式
    typescript 属性默认值使用箭头函数 this指向问题
    presto 函数中使用子查询
    浅谈redis的HyperLogLog与布隆过滤器
    关于管理后台更新与响应的设计
    对“算法-求二进制数中1的个数” 中一些要点的补充
    关于async 中return 和 return await 的差异
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647123.html
Copyright © 2011-2022 走看看