zoukankan      html  css  js  c++  java
  • Linux网络编程(多人在线聊天系统)

    一、首先是服务器的建立

           首先是一个信号终止程序,发信号ctrl+c终止程序,而是是初始化网络通信.

           创建一个描述符负责绑定服务器和监听服务器接收客户端的消息.

           socket()->sockaddr_in->bind->listen(准备就绪)

           开始接收客户端消息.start()函数

           首先是声明一个结构体用来存储客户端的消息,利用accept()函数来创建一个新的

           描述符来接收,这里有阻塞效果,也即是说连接的时候只能一个一个的连.

           然后是分离线程处理这个sockfd的连接.

           pthread_create(&pid,0,pthread_deal,&sockfd1);

           线程主要是先做线程的分离,然后是取得它们的sockfd描述符,把这个客户端的信息

           存储到一个结构体数组中.然后是调用循环发送到各个客户端的函数,来发送消息.

           当接收函数recv(sockfd,buf,sizeof(buf)) == 0 的时候,表示有客户端退出,这时

           就把这个在结构体数组的相应的fd置为0

          

    #include "server.h"
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    
    int sockfd; //服务器本身的描述符
    struct User u[200] = {}; //用来保存用户的信息
    int size;//数组的下标,同时也是客户端的个数
    
    void init(void) //通信准备工作
    {
        printf("聊天室服务器马上启动....
    ");
        sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(-1 == sockfd)
        {
            perror("fail to socket");
            printf("服务器故障!
    ");
            exit(-1);
        }
        //准备通信地址和绑定服务器
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(2222); //端口的值,转换成网络的格式
        addr.sin_addr.s_addr = inet_addr("172.16.1.21");
        if(-1 == bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)))
        {
            perror("fail to bind");
            exit(-1);
        }
        printf("bind is ok,欢迎访问!
    ");
        //设置监听
        if(-1 != listen(sockfd,200))
        {
            printf("监听已经设置,一切准备就绪!
    ");
        }
    }
    
    void send_msg(char *p_msg) //发送消息的函数
    {
        int num = 0;
        for(num = 0;num < size;num++)
        {
            if(u[num].fd) //如果是有效的时候才发送
            {
                send(u[num].fd,p_msg,sizeof(p_msg),0);
            }
        }
    }
    
    void* pthread_deal(void* p) //线程处理函数
    {
        pthread_detach(pthread_self());
        int fd2 = *(int*)p; //取得客户端的sockfd
        u[size].fd = fd2;  //放入结构体中
        char name[20] = {};
        int res = recv(fd2,name,sizeof(name),0);
        if(res > 0)
        {
            strcpy(u[size].name,name);//存放用户名
        }
        size++;
        char user[100] = {};
        sprintf(user,"%s悄悄的进来了!(*^__^*) 嘻嘻……
    ",name);
        send_msg(user);
        while(1)
        {
            if(recv(fd2,name,sizeof(name),0) == 0) /*返回0表示有客户端退出*/
            {
                u[size-1].fd = 0; //把退出的客户端的结构描述符置换成0
            }
        }
    }
    
    void start(void)
    {
        printf("success to start server,let's go!
    ");
        while(1)
        {
            struct sockaddr_in client;//存储接收到的客户端的信息
            socklen_t length = sizeof(client);
            //接收客户端的信息,会有阻塞效果,sockfd1标记客户端
            int sockfd1 = accept(sockfd,(struct sockaddr*)&client,&length);
            if(sockfd1 == -1)
            {
                perror("fail to accept!");
                continue;  //继续连接
            }
            printf("%s连接上来了
    ",inet_ntoa(client.sin_addr));
            /*连接成功之后,就启动线程*/
            pthread_t pid;//线程id
            pthread_create(&pid,0,pthread_deal,&sockfd1);
        }
    }
    
    void sig_exit(int signo ) //子定义信号关闭服务器函数
    {
        close(sockfd);//关闭服务器端口
        printf("服务器成功关闭!
    ");
        exit(0);
    }
    int main(void)
    {
        printf("按ctrl+c关闭聊天室服务器!
    ");
        signal(SIGINT,sig_exit);
        init();//初始化,服务器通信准备工作
        start();//启动服务(开始处理聊天信息)
        return 0;
    }

    2.客户端的编写.

      

          

  • 相关阅读:
    nginx upstream permission denied错误解决
    基于Mariadb 10.6.4在CentOS 7环境下配置Galera Cluster集群
    K8s 开始
    RTSP H264/HEVC 流 Wasm 播放
    Netty编码示例(RPC & WbeSocket & Tomcat)
    Netty异步任务调度与异步线程池
    Netty编解码器&TCP粘包拆包
    Netty核心模块组件
    Neety编码示例(群聊系统&⼼跳检测&WebSocket⻓连接)
    Netty高性能架构设计
  • 原文地址:https://www.cnblogs.com/yasanlun/p/3857310.html
Copyright © 2011-2022 走看看