zoukankan      html  css  js  c++  java
  • Linux Socket多线程实现简单的多人聊天(pend)

    Server:

    设置可聊天数为5,为每一个client创建一个线程,这个线程负责接收client的聊天内容并发给其他用户看。

    用mutex同步各个线程修改聊天室空余聊天位。

    Client:

    主线程负责向server发送自己的内容,开一个线程负责接收server发过来别人聊天的内容。

    client.c

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/un.h>
    #include <sys/time.h>
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <pthread.h>
    
    char recv_buf[1500],send_buf[1024];
    
    void pthread_function(void* sock_fd){
        int sockfd=*(int*)sock_fd;
        long recvbytes;
        while(1) {
            if((recvbytes=recv(sockfd,recv_buf,1500,0))==-1){
                printf("recv error");
                exit(1);
            }
            else{
                recv_buf[recvbytes]='';
                printf("%s
    ",recv_buf);
            }
        }
    } 
    int main(void){
        pthread_t id;
        int sockfd;
        struct sockaddr_in sever_addr;
    
        sever_addr.sin_family=AF_INET;
        sever_addr.sin_port=htons(12363);
        sever_addr.sin_addr.s_addr=inet_addr("10.144.20.79");
    
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
            printf("socket error");
            exit(1);
        }
        if(connect(sockfd,(struct sockaddr*)&sever_addr,sizeof(sever_addr))==-1){
            printf("connect error");
            exit(1);
        }
        char name[20];
        printf("please input your name
    ");
        scanf("%s",name);
        send(sockfd,name,strlen(name),0);
    
        if(pthread_create(&id,NULL,(void*)pthread_function,(void*)&sockfd)!=0)
            printf("create thread error
    ");
        while(1){
            scanf("%s",send_buf);
            fflush(stdin);
            if(send(sockfd,send_buf,strlen(send_buf),0)==-1){
                printf("send error");
                exit(1);
            }
            sleep(1);
        }
        close(sockfd);
        pthread_cancel(id);
        return 0;
    }

    server.c

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/un.h>
    #include <sys/time.h>
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <pthread.h>
    
    
    #define COUNT 5
    int socket_fd[COUNT]={0,-1,-1,-1,-1};
    pthread_mutex_t emptymutex;
    
    int empty=5;
    /*
    the fuction for the thread
    */
    
    void pthread_function(void* clientfd){
        char message[1500];
        char buf[1024];
        int i;
        long recvbytes;
        char name[20];
        int client_fd=*(int*)clientfd;
    
        pthread_mutex_lock(&emptymutex);
        if(empty>0)
            empty--;
        else pthread_exit(NULL);
        pthread_mutex_unlock(&emptymutex);
    
    
    
        /*first connect,need to save the name of clients*/
        recvbytes=recv(client_fd,name,20,0);
        name[recvbytes]=':';
        name[recvbytes+1]='';
        send(client_fd,"welcome to this chatroom,enjoy chatting:",100,0);
    
    
        while(1){
            if((recvbytes=recv(client_fd,buf,1024,0))==-1){
                perror("recv");
                pthread_exit(NULL);
            }
            if(recvbytes==0){
                printf("%sbye
    ",name);
                break;
            }
            buf[recvbytes]='';
            for (i = 0; i < COUNT; ++i)
            {
                int tmpclient=socket_fd[i];
                if(tmpclient!=-1){
                    message[0]='';
                    strcat(message,name);
                    strcat(message,buf);
                    if(send(tmpclient,message,strlen(message),0)==-1){
                        perror("send error");
                        pthread_exit(NULL);
                    }
                }
            }
        }
        //close socket and reset the fd -1 
        close(client_fd);
    
        pthread_mutex_lock(&emptymutex);
        if(empty<5)
            empty++;
        else pthread_exit(NULL);
        pthread_mutex_unlock(&emptymutex);
        for (i = 0; i < COUNT; ++i)
        {
            if(socket_fd[i]==client_fd)
                socket_fd[i]=-1;
        }
        pthread_exit(NULL);
    }
    
    
    int main(){
        int i;
        pthread_mutex_init(&emptymutex,NULL);
    
        pthread_t id;
        int sockfd,client_fd;
        socklen_t sin_size;
        struct sockaddr_in my_addr;
        struct sockaddr_in remote_addr;
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
            perror("socket");
            exit(1);
        }
    
        my_addr.sin_family=AF_INET;
        my_addr.sin_port=htons(12363);
        my_addr.sin_addr.s_addr=htonl(INADDR_ANY);
        bzero(&(my_addr.sin_zero),8);
    
    
        if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))==-1){
            perror("bind");
            exit(1);
        }
    
        if(listen(sockfd,10)==-1){
            perror("listen");
            exit(1);
        }
    
        i=0;
        while(1){
            sin_size=sizeof(struct sockaddr_in);
            if((client_fd=accept(sockfd,(struct sockaddr*)&remote_addr,&sin_size))==-1){
                perror("accept");
                exit(1);
            }
            if(empty>0){    
                while(socket_fd[i]==-1)
                    i=(i+1)%COUNT;
                socket_fd[i]=client_fd;
                pthread_create(&id,NULL,(void*)pthread_function,(void*)&client_fd);}
            else break;
        }
        pthread_mutex_destroy(&emptymutex);
        return 0;    
    }

    注意点:

    • sockaddr和sockaddr_in的区别
    • htonl(INADDR_ANY)设置ip为0.0.0.0,这样会监听所有端口
    • server是:socket-bind-listen-accpet-send/recv-close;client是:socket-connect-send/recv-close。
    • pthread_create()第三个参数是void*,如果想用int,可以int var=*(int*)client_fd
    • bind:address in use是端口已经被打开
    • 线程里用pthread_exit(NULL)如果用exit连主线程都会退出

    还要改,现在新开一个client可以接受老client的内容,但是老client接收不到新client的内容。还有就是client输入一个什么特定的字符表示结束,以close(socket).

  • 相关阅读:
    第四周课下作业
    # 20165206 2017-2018-2 《Java程序设计》第4周学习总结
    20165206 2017-2018-2 《Java程序设计》第三周学习总结
    20165206 2017-2018-2 《Java程序设计》第二周学习总结
    第一周学习总结
    20165206 预备作业3 Linux安装及学习
    20165206学习基础和C语言基础调查
    20165206 我期望的师生关系
    channelartlist标签调用实例
    dede如何按自己写的ID进行排序
  • 原文地址:https://www.cnblogs.com/LUO77/p/5707511.html
Copyright © 2011-2022 走看看