zoukankan      html  css  js  c++  java
  • (OK) server-client-pthread-c language

    server.c


    
        // gcc -lpthread server.c -o server
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <string.h>
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <sys/socket.h>
        #include <pthread.h>
    
    
        //#endif
        #define BUF_SIZE 1024        //默认缓冲区
        #define SERVER_PORT 11111    //监听端口
        #define SERVER_HOST "127.0.0.1"    //服务器IP地址
        #define EPOLL_RUN_TIMEOUT -1    //epoll的超时时间
        #define EPOLL_SIZE 10000    //epoll监听的客户端的最大数目
        #define LISTEN_SIZE 10        //监听队列长度
    
        #define STR_WELCOME "Welcome to seChat! You ID is : Client #%d"
        #define STR_MESSAGE "Client #%d>> %s"
        #define STR_NOONE_CONNECTED "Noone connected to server expect you!"
        #define CMD_EXIT "EXIT"
    
        //两个有用的宏定义:检查和赋值并且检测
        #define CHK(eval) if(eval < 0){perror("eval"); exit(-1);}
        #define CHK2(res, eval) if((res = eval) < 0){perror("eval"); exit(-1);}
    
        void* handle_message(void *arg);
    
        int main(int argc, char *argv[])
        {
            int listener;        //监听socket
            struct sockaddr_in addr, peer;
            addr.sin_family = PF_INET;
            addr.sin_port = htons(SERVER_PORT);
            addr.sin_addr.s_addr = inet_addr(SERVER_HOST);
            socklen_t socklen;
            socklen = sizeof(struct sockaddr_in);
    
            int client;
    
            CHK2(listener, socket(PF_INET, SOCK_STREAM, 0));    //初始化监听socket
    
            // 设置套接字选项避免地址使用错误
            int on=1;
            if((setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
            {
                perror("setsockopt failed");
                exit(EXIT_FAILURE);
            }
    
            CHK(bind(listener, (struct sockaddr *)&addr, sizeof(addr)));    //绑定监听socket
    
            //printf("listen
    ");
            CHK(listen(listener, LISTEN_SIZE));    //设置监听
            printf("listening
    ");
    
            while (1) {
                //printf("accept
    ");
                CHK2(client, accept(listener, (struct sockaddr *)&peer, &socklen));
                printf("accepted
    ");
    
                pthread_t reader;
                int rt = pthread_create(&reader, NULL, handle_message, (void *)&client);
                if (-1 == rt) {
                    printf("thread creation error
    ");
                    return -1;
                }
            }
        }
    
        void* handle_message(void *arg)
        {
            int client = *((int*)arg);
            //sleep(5);
            char buf[BUF_SIZE];
            int len;
    
            while(1){
                bzero(buf, BUF_SIZE);
                CHK2(len, recv(client, buf, BUF_SIZE, 0));    //接受客户端信息
                if (len == 0)        //客户端关闭或出错,关闭socket,并从list移除socket
                {
                    printf("close-client: %d
    ", client);
                    CHK(close(client));
                    return NULL;
                } else            //向客户端发送信息
                {
                    CHK(send(client, STR_NOONE_CONNECTED, strlen(STR_NOONE_CONNECTED), 0));
                    printf("receive: %s from %d
    ", buf, client);
                }
            }
            //return len;
            //return NULL;
        }
    
    

    client.c

    
        // gcc client.c -o client
        // gcc -lpthread client.c -o client
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <string.h>
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <sys/socket.h>
        #include <sys/epoll.h>
    
        //#endif
        #define BUF_SIZE 1024        //默认缓冲区
        #define SERVER_PORT 11111    //监听端口
        #define SERVER_HOST "127.0.0.1"    //服务器IP地址
        #define EPOLL_RUN_TIMEOUT -1    //epoll的超时时间
        #define EPOLL_SIZE 10000    //epoll监听的客户端的最大数目
    
        #define STR_WELCOME "Welcome to seChat! You ID is : Client #%d"
        #define STR_MESSAGE "Client #%d>> %s"
        #define STR_NOONE_CONNECTED "Noone connected to server expect you!"
        #define CMD_EXIT "EXIT"
    
        //两个有用的宏定义:检查和赋值并且检测
        #define CHK(eval) if(eval < 0){perror("eval"); exit(-1);}
        #define CHK2(res, eval) if((res = eval) < 0){perror("eval"); exit(-1);}
    
        char message[BUF_SIZE];
    
        /*
            流程:
                调用fork产生两个进程,两个进程通过管道进行通信
                子进程:等待客户输入,并将客户输入的信息通过管道写给父进程
                父进程:接受服务器的信息并显示,将从子进程接受到的信息发送给服务器
        */
        int main(int argc, char *argv[])
        {
            int sock, pid, pipe_fd[2], epfd;
    
            struct sockaddr_in addr;
            addr.sin_family = PF_INET;
            addr.sin_port = htons(SERVER_PORT);
            addr.sin_addr.s_addr = inet_addr(SERVER_HOST);
    
            static struct epoll_event ev, events[2];
            ev.events = EPOLLIN | EPOLLET;
    
            //退出标志
            int continue_to_work = 1;
    
            CHK2(sock, socket(PF_INET, SOCK_STREAM, 0));
            CHK(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0);
    
            CHK(pipe(pipe_fd));
    
            CHK2(epfd, epoll_create(EPOLL_SIZE));
    
            ev.data.fd = sock;
            CHK(epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev));
    
            ev.data.fd = pipe_fd[0];
            CHK(epoll_ctl(epfd, EPOLL_CTL_ADD, pipe_fd[0], &ev));
    
            // 调用fork产生两个进程
            CHK2(pid, fork());
            switch (pid) {
            case 0:        // 子进程
                close(pipe_fd[0]);    // 关闭读端
                printf("Enter 'exit' to exit
    ");
                while (continue_to_work) {
                    bzero(&message, BUF_SIZE);
                    fgets(message, BUF_SIZE, stdin);
    
                    // 当收到exit命令时,退出
                    if (strncasecmp(message, CMD_EXIT, strlen(CMD_EXIT)) == 0) {
                        continue_to_work = 0;
                    } else {
                        CHK(write(pipe_fd[1], message, strlen(message) - 1));
                    }
                }
                break;
            default:        // 父进程
                close(pipe_fd[1]);    // 关闭写端
                int epoll_events_count, res;
                while (continue_to_work) {
                    CHK2(epoll_events_count, epoll_wait(epfd, events, 2, EPOLL_RUN_TIMEOUT));
    
                    for (int i = 0; i < epoll_events_count; i++) {
                        bzero(&message, BUF_SIZE);
                        if (events[i].data.fd == sock)    //从服务器接受信息
                        {
                            CHK2(res, recv(sock, message, BUF_SIZE, 0));
                            if (res == 0)    //服务器已关闭
                            {
                                CHK(close(sock));
                                continue_to_work = 0;
                            } else {
                                printf("%s
    ", message);
                            }
                        } else    //从子进程接受信息
                        {
                            CHK2(res, read(events[i].data.fd, message, BUF_SIZE));
                            if (res == 0) {
                                continue_to_work = 0;
                            } else {
                                CHK(send(sock, message, BUF_SIZE, 0));
                            }
                        }
                    }
                }
            }
            if (pid) {
                close(pipe_fd[0]);
                close(sock);
            } else {
                close(pipe_fd[1]);
            }
    
            return 0;
        }
    
    


  • 相关阅读:
    NET Attribute
    net core HttpClient
    Nuget服务器
    JS-防抖节流
    Codeforces,Topcoder,SGU,Timus,ProjectEuler
    并发编程,高速缓存,原子操作,指令重排序
    C编译器的编译过程主要分成四步: (1) 预处理 (2) 编译 (3) 汇编 (4) 连接
    C#--Distinct
    PageRank算法的思想
    ML.NET 发布0.11版本:.NET中的机器学习,为TensorFlow和ONNX添加了新功能
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647020.html
Copyright © 2011-2022 走看看