(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\n");
        CHK(listen(listener, LISTEN_SIZE));    //设置监听
        printf("listening\n");

        while (1) {
            //printf("accept\n");
            CHK2(client, accept(listener, (struct sockaddr *)&peer, &socklen));
            printf("accepted\n");

            pthread_t reader;
            int rt = pthread_create(&reader, NULL, handle_message, (void *)&client);
            if (-1 == rt) {
                printf("thread creation error\n");
                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\n", client);
                CHK(close(client));
                return NULL;
            } else            //向客户端发送信息
            {
                CHK(send(client, STR_NOONE_CONNECTED, strlen(STR_NOONE_CONNECTED), 0));
                printf("receive: %s from %d\n", 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\n");
            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\n", 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;
    }



posted @ 2016-04-02 09:13  张同光  阅读(95)  评论(0编辑  收藏  举报