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;
        }
    
    


  • 相关阅读:
    android数据恢复
    UVA 690 Pipeline Scheduling
    2017 国庆湖南 Day4
    2017 国庆湖南 Day5
    2017 国庆湖南 Day6
    2017国庆 清北学堂 北京综合强化班 Day1
    2017 国庆湖南Day2
    bzoj 2962 序列操作
    UVA 818 Cutting Chains
    UVA 211 The Domino Effect
  • 原文地址:https://www.cnblogs.com/ztguang/p/12647020.html
Copyright © 2011-2022 走看看