C语言实现--基于UDP的多人在线聊天室

这篇具有很好参考价值的文章主要介绍了C语言实现--基于UDP的多人在线聊天室。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

实现功能

实现思想

实现代码(部分及详解)

服务端部分代码

客户端部分代码

实现效果

项目中出现的问题和解决方法

项目整体代码展示

代码优化思路

服务端代码

客户端代码


实现功能

  1. 服务端可以同时连接多个客户端;
  2. 新的客户端连接服务端时,可以在服务端显示自己的名字并提示登陆成功;
  3. 新客户端登陆成功时,其他客户端也会提示有新用户登陆;
  4. 客户端发送消息时,服务器内可以提示是哪个客户端发送了消息;
  5. 客户端发送消息时,其他客户端也可以接收到该客户端发送的消息内容;
  6. 服务端相当于主机,客户端相当于用户。

实现思想

  1. 客户端可以发送三种消息:登录消息(用户名),聊天消息,退出消息,所以需要定义枚举类型,包含这三种消息,当发送对应的消息内容时,将消息类型一起发送,接收消息的一端可以根据消息类型进入不同的函数进行处理。
  2. 服务器主要的功能就是转发消息,将某一用户发送的消息转发给其他用户,包括用户的登录,聊天和退出消息,还要可以给所有的用户主动发送通知。
  3. 聊天室要实现的是支持多人同时在线聊天,所以就需要使用链表的思想,将加入的用户依次链接,发送消息时依次遍历,退出时方便找到对应用户。
  4. 服务端和客户端都需要有发送消息和接收消息的功能,两种功能互不影响,所以需要创建子进程,由父进程完成消息的发送处理,由子进程完成消息的接收处理。
  5. 重点还是理解链表的思想。

实现代码(部分及详解)

服务端部分代码

        1. 定义枚举的三种消息类型:

  • 登录Login;
  • 聊天Chat;
  • 退出Quit。
//消息类型
enum type_t
{
    Login = 1, //登录
    Chat,      //聊天
    Quit,      //退出
};

        2. 定义描述发送的消息内容的结构体:

  • 消息类型type(枚举中的三种消息);
  • 姓名name(用户名);
  • 消息正文text(聊天信息以及退出消息)。

        将姓名和消息正文分开定义的原因是,用户发送消息时,需要体现出是哪个用户发送的消息,而且用户登录时要先取名,再发消息正文,如果使用一个定义的话,用户名会被消息正文覆盖。

//定义描述消息结构体
typedef struct msg_t
{
    int type;       //消息类型:登录  聊天  退出
    char name[32];  //姓名
    char text[128]; //消息正文
} MSG_t; //将结构体名重定义为MSG_t

        3. 定义链表的节点结构体:根据链表的特性,定义用户地址作为数据域,定义结构体指针作为指针域。

//链表的节点结构体
typedef struct node_t
{
    struct sockaddr_in addr; //数据域
    struct node_t *next;     //指针域
} link_t;

        4.主函数中子进程实现消息的发送处理:

  • 服务端不需要退出,所以使用while一直循环在子进程和父进程中,也不需要break跳出处理;
  • 子进程中需要接收消息并判断接收到消息的类型,然后根据消息类型调用对应的处理函数。
//创建一个空的有头单向链表
link_t *p = createLink();
while (1) 
{
   //接收客户端消息
   if(recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&clientaddr,&len) < 0)
     {
        perror("recvfrom err.");
        return -1;
     }
    //判断消息类型,调用对应函数
     switch (msg.type)
     {
        case Login: //登录
          client_login(sockfd, p, clientaddr, msg);
          break;
        case Chat:  //聊天
          client_chat(sockfd, p, clientaddr, msg);
          break;
        case Quit:  //退出
          client_quit(sockfd, p, clientaddr, msg);
          break;
     }
}

        5.主函数中父进程实现消息的接收处理:

  • 父进程发送消息时,记得处理字符串尾部的换行符,否则客户端每次接收到消息后,都会多打印一个换行。
while (1) //服务器发通知
{
   msg.type = Chat;
   //给结构体中的数组成员变量赋值,一般使用strcpy进行赋值
   strcpy(msg.name, "server");
   //获取终端输入
   fgets(msg.text, sizeof(msg.text), stdin);
   //解决发送信息时,会将换行符发送过去的问题
   if (msg.text[strlen(msg.text) - 1] == '\n')
       msg.text[strlen(msg.text) - 1] = '\0';
   //将信息发送给同一局域网的其他客户端
   sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
                   sizeof(serveraddr));
}

        6. 用户登录函数:

  • 用户登录时,会将用户自己的地址和用户名一起发送给服务端,所以在服务端函数中可以循环遍历链表,来告诉已经登录的其他用户新登录的用户是谁。
  • 然后将新登录的用户保存到当前的链表结尾。
  • 需要传递给该函数的参数有(其他函数也是这些形参):
    • 套接字描述符(因为要在函数中给其他用户发送消息);
    • 链表(头)指针(因为要遍历链表和创建新节点);
    • 新登录的用户地址(新用户加入链表时需要将用户地址保存到节点的数据域);
    • 消息结构体对象(MSG_t,函数中发送消息时需要发送新用户的名字和消息正文)。
//登录函数
void client_login(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg)
{
    //1.告诉其他用户登录的新用户是谁
    strcpy(msg.name,"server"); //发送消息的人是服务端
    sprintf(msg.text, "%s login!", msg.name); //服务端发送新登陆的用户名
    //循环发送给之前已经登陆的用户
    while (p->next != NULL)
    {
        p = p->next;
        sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), 
                    sizeof(p->addr));
    }

    //上面的代码运行结束后,此时链表指针已经指向了最后一个用户

    //2.创建一个新节点保存新连接的客户端地址 ,连接到链表结尾
    link_t *pnew = (link_t *)malloc(sizeof(link_t));
    if (pnew == NULL)
    {
        perror("malloc new node err.");
    }
    //初始化
    pnew->addr = clientaddr;
    pnew->next = NULL;
    //链接  p是最后一个节点的地址
    p->next = pnew;
}

        7. 聊天消息发送函数:

  • 用户发送聊天消息时,要将消息发送给链表中的,除了自己以外的其他所有用户,当然也要在服务端上打印;
  • 判断链表中是否为发送消息用户时,使用了memcmp函数。

int memcmp(const void *buf1, const void *buf2, unsigned int count);

功能:比较内存区域buf1和buf2的前count个字节;

参数:内存区buf1,内存区buf2,比较字节数count;

返回值:如果buf1 < buf2 则返回小于0的数,

如果buf1 = buf2 则返回0,

如果buf1 > buf2 则返回大于01的数;

//聊天信息发送函数
void client_chat(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg)
{
    //从链表头开始遍历
    while (p->next != NULL)
    {
        p = p->next;

        if(memcmp(&(p->addr), &clientaddr, sizeof(clientaddr)) != 0)
        {
            //只要判断出用户地址和发送消息的用户地址不同,就将消息发送给该用户
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr),
                   sizeof(p->addr));
        }
    }
    //在服务器中打印发送的消息,“谁说了什么”
    printf("%s said %s\n", msg.name, msg.text);
}

        8. 用户退出处理函数:

  • 用户退出时,还是要在服务端遍历链表,而且是需要全部遍历;
  • 如果遍历到退出的那个用户,则将该用户对应的链表节点删除;
  • 如果遍历到其他用户,则依次发送用户要退出的信息。
//退出函数
void client_quit(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg)
{
    link_t *pdel = NULL;
    //从头开始遍历查找要删除的节点
    while (p->next != NULL)
    {
        //如果循环到的地址是要删除的用户,则删除该节点
        if (memcmp(&(p->next->addr), &clientaddr, sizeof(clientaddr)) == 0)
        {
            //删除指定用户
            pdel = p->next;
            p->next = pdel->next;

            free(pdel);
            pdel = NULL;
        }
        else
        {
            //如果不是要删除的用户,则向其发送指定用户要删除的消息
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->next->addr),
                   sizeof(p->next->addr));
            p = p->next;
        }
    }
}

客户端部分代码

        1. 客户端和服务端一样需要定义枚举消息类型,和描述消息结构体类型;

        2. 在客户端中,一进入主函数,就应该进行用户的登录,向服务端发送登录信息

  • 主要是发送用户的地址和名字;
  • 名字只是为了提示服务端和其他用户,有新用户登录;
  • 服务端会将新用户的地址连接到链表结尾。
MSG_t msg;
//UDP客户端不用bind地址,可以直接发送自己的登陆消息
msg.type = Login; //登录
printf("please input login name>>");
fgets(msg.name, sizeof(msg.name), stdin);
if (msg.name[strlen(msg.name) - 1] == '\n')
    msg.name[strlen(msg.name) - 1] = '\0';
/*UDP客户端不用绑定地址,可以直接发送自己的登陆消息,
    只需要在sendto的参数中填写接收方的地址*/
sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
       sizeof(serveraddr));

        3. 主进程中创建子进程并实现发送消息的功能

  • 用户发送的消息中,主要是聊天消息和退出消息 “quit” 。
  • 如果发送的消息字符串是 “quit” ,则先将该用户要退出的信息发送给服务端,然后再杀死父进程,子进程跳出循环后,在程序运行结束时被释放。
  • 如果发送的消息是正常的聊天信息,则只发送给服务端,然后子进程继续运行。
while (1) //发
{
    fgets(msg.text, sizeof(msg.text), stdin);
    if (msg.text[strlen(msg.text) - 1] == '\n')
                msg.text[strlen(msg.text) - 1] = '\0';
    //判断发送的消息是否为“quit”退出消息
    if (strncmp(msg.text, "quit", 4) == 0)
            {
                msg.type = Quit;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
                       sizeof(serveraddr));
                //杀死父进程
                kill(getppid(), SIGKILL);
                //退出循环,子进程结束
                break;
            }else{
                msg.type = Chat;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
                       sizeof(serveraddr));
            }
}

        4. 父进程中实现接收消息的功能

  • 用户接收到服务端转发的消息时,会在自己的界面打印,且会打印出详细信息,比如 “谁说了什么话” 。
while (1) //收
{
    if (recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL) < 0)
            {
                perror("recvfrom err.");
                return -1;
            }
    printf("%s said %s\n", msg.name, msg.text);
}

实现效果

        1. 运行服务端后,运行客户端进行连接;

  • 客户端成功连接服务端后,在服务端上显示用户名,以及新用户连接成功的消息;

C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室

  • 客户端向服务端发送消息,服务端可以打印用户名以及消息内容(我在客户端发消息时,测试打印了进程号,s 是子进程号,f 是父进程号);

C语言实现--基于UDP的多人在线聊天室

C语言实现--基于UDP的多人在线聊天室

         2. 连接第二个客户端;

  • 连接成功后,服务端会打印第二个客户端的用户名并提示连接成功,并且第一个用户也会提示新用户的连接;sprintf(msg.text, "%s login", msg.name);
        strcpy(msg.name, "server");

C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室

  • 不管是第一个用户发送消息还是第二个用户发送消息,另一个用户都能收到该消息,并且会提示是哪个用户发送的消息;

C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室

        3.连接第三个客户端

  • 三个客户端的实现效果

C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室C语言实现--基于UDP的多人在线聊天室

项目中出现的问题和解决方法

        问题一:a用户退出时,只会通知其他用户a用户退出,在服务端不显示a用户退出;

        解决上述问题后,当登陆的用户大于2时,除了最后一个用户退出时还是有上述问题,其他用户退出时都正常;

        上述两个问题可以用一句打印用户信息的代码解决,只不过需要将这句代码需要放到程序正确的位置,否则实现了问题1后很容易出现问题2,所以需要添加一句“printf("%s quit.\n", msg.name);”,而且要添加到“服务端程序中的用户退出函数的删除链表节点的代码中”或“服务端程序主函数中的switch判断消息类型是Quit的操作代码中”。

        问题二:客户端程序中,在子进程中一开始写了一句杀死父进程的代码,后来发现可能会出现孤儿进程的问题;

        尝试运行了一下之后,发现输入quit退出用户的时候,终端输出“killed”,表示父进程已被结束,而且使用命令查看进程时,子进程和父进程确实都已经退出,且查看后台进程时,子进程也不存在;后来分析代码发现,子进程杀死父进程之后,就跳出了while循环,然后程序向下依次运行,最后运行到“return 0”,子进程也正常结束;也可以在子进程的break上面加一句“exit(0)”保证子进程先退出,在向下运行到程序结束。

项目整体代码展示

代码优化思路

        我在编写代码时,只编写了两个文件,所以两个文件中有部分重复代码,而且服务端的函数全部跟主函数声明实现在一起,所以有以下优化思路:

  • 创建一个 “.h” 文件,将枚举的定义和描述消息的结构体定义放入该文件,且将服务端中函数的声明和实现放入该文件,服务端和客户端在头文件中包含该“.h”文件;
  • Makefile文件中补充“.h”文件;

        这里只展示优化前的代码;文章来源地址https://www.toymoban.com/news/detail-444314.html

服务端代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <signal.h>

//消息类型
enum type_t
{
    Login = 1, //登录
    Chat,      //聊天
    Quit,      //退出
};

//定义描述消息结构体
typedef struct msg_t
{
    int type;       //消息类型:登录  聊天  退出
    char name[32];  //姓名
    char text[128]; //消息正文
} MSG_t;

//链表的节点结构体
typedef struct node_t
{
    struct sockaddr_in addr; //数据域
    struct node_t *next;     //指针域
} link_t;

link_t *createLink(void);
void client_login(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg);
void client_chat(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg);
void client_quit(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg);

int main(int argc, char const *argv[])
{
    int sockfd;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }

    //填充服务器的ip和port
    struct sockaddr_in serveraddr, clientaddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[1]));
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

    socklen_t len = sizeof(clientaddr);

    if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    {
        perror("bind err.");
        return -1;
    }
    MSG_t msg;
    //创建子进程,父进程接收客户端的信息并处理,子进程转发消息
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork err.");
        return -1;
    }
    else if (pid == 0)
    {
        //创建一个空的有头单向链表
        link_t *p = createLink();
        while (1) //收到客户端的请求,处理请求
        {
            if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&clientaddr, &len) < 0)
            {
                perror("recvfrom err.");
                return -1;
            }
            switch (msg.type)
            {
            case Login: //登录
                client_login(sockfd, p, clientaddr, msg);
                break;
            case Chat:
                client_chat(sockfd, p, clientaddr, msg);
                break;
            case Quit:
                client_quit(sockfd, p, clientaddr, msg);
                break;
            }
        }
    }
    else
    {
        while (1) //服务器发通知
        {
            msg.type = Chat;
            //给结构体中的数组成员变量赋值,一般使用strcpy进行赋值
            strcpy(msg.name, "server");
            //获取终端输入
            fgets(msg.text, sizeof(msg.text), stdin);
            //解决发送信息时,会将换行符发送过去的问题
            if (msg.text[strlen(msg.text) - 1] == '\n')
                msg.text[strlen(msg.text) - 1] = '\0';
            //将信息发送给同一局域网的其他客户端
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
                   sizeof(serveraddr));
        }
    }
    //程序结束时,关闭套接字描述符
    close(sockfd);
    return 0;
}

//链表函数 -- 创建一个空的有头单向链表
link_t *createLink(void)
{
    link_t *p = (link_t *)malloc(sizeof(link_t));
    if (p == NULL)
    {
        perror("malloc head node err.");
        return NULL;
    }
    p->next = NULL;
    return p;
}

//登录函数 -- 将客户端的clientaddr保存到链表中,循环链表告诉其他用户谁登录了
void client_login(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg)
{
    //1.告诉其他用户登录的新用户是谁
    strcpy(msg.name,"server"); //发送消息的人是服务端
    sprintf(msg.text, "%s login!", msg.name); //服务端发送新登陆的用户名
    //循环发送给之前已经登陆的用户
    while (p->next != NULL)
    {
        p = p->next;
        sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
    }
    //上面的代码运行结束后,此时链表指针已经指向了最后一个用户
    //2.创建一个新节点保存新连接的客户端地址 ,连接到链表结尾
    link_t *pnew = (link_t *)malloc(sizeof(link_t));
    if (pnew == NULL)
    {
        perror("malloc new node err.");
    }
    //初始化
    pnew->addr = clientaddr;
    pnew->next = NULL;
    //链接  p是最后一个节点的地址
    p->next = pnew;
}

//聊天信息发送函数 -- 将消息转发给所有的用户,除去发送消息的自己
void client_chat(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg)
{
    //从链表头开始遍历
    while (p->next != NULL)
    {
        p = p->next;
        //memcmp函数,比较内存区域a和b的前n个字节
        //参数--区域a,区域b,比较字节数n
        //返回值--a<b返回负数,a=b返回0,a<b返回正数
        if(memcmp(&(p->addr), &clientaddr, sizeof(clientaddr)) != 0)
        {
            //只要判断出用户地址和发送消息的用户地址不同,就将消息发送给该用户
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->addr),
                   sizeof(p->addr));
        }
    }
    //在服务器中打印发送的消息
    printf("%s said %s\n", msg.name, msg.text);
}

//退出函数 -- 将客户端的clientaddr从链表中删除,循环链表告诉其他用户谁退出了
void client_quit(int sockfd, link_t *p, struct sockaddr_in clientaddr, MSG_t msg)
{
    link_t *pdel = NULL;
    //从头开始遍历查找要删除的节点
    while (p->next != NULL)
    {
        //如果循环到的地址是要删除的用户,则删除
        if (memcmp(&(p->next->addr), &clientaddr, sizeof(clientaddr)) == 0)
        {
            //删除指定用户
            pdel = p->next;
            p->next = pdel->next;

            free(pdel);
            pdel = NULL;
        }
        else
        {
            //如果不是要删除的用户,则向其发送指定用户要删除的消息
            sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&(p->next->addr),
                   sizeof(p->next->addr));
            p = p->next;
        }
    }
}

客户端代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <signal.h>

//消息类型
enum type_t
{
    Login = 1, //登录
    Chat,      //聊天
    Quit,      //退出
};

//定义描述消息结构体
typedef struct msg_t
{
    int type;       //消息类型:登录  聊天  退出
    char name[32];  //姓名
    char text[128]; //消息正文
} MSG_t;


int main(int argc, char const *argv[])
{
    int sockfd;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }

    //填充结构体
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);

    MSG_t msg;
    //UDP客户端不用bind地址,可以直接发送自己的登陆消息
    msg.type = Login; //登录
    printf("please input login name>>");
    fgets(msg.name, sizeof(msg.name), stdin);
    if (msg.name[strlen(msg.name) - 1] == '\n')
        msg.name[strlen(msg.name) - 1] = '\0';

    sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
           sizeof(serveraddr));
    //创建父子进程:父进程收消息 子进程发送消息
    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork err.");
        return -1;
    }
    else if (pid == 0)
    {
        while (1) //发
        {
            fgets(msg.text, sizeof(msg.text), stdin);
            if (msg.text[strlen(msg.text) - 1] == '\n')
                msg.text[strlen(msg.text) - 1] = '\0';
            //判断发送的消息是否为“quit”退出消息
            if (strncmp(msg.text, "quit", 4) == 0)
            {
                msg.type = Quit;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
                       sizeof(serveraddr));
                //杀死父进程
                kill(getppid(), SIGKILL);
                //退出循环,子进程结束
                break;
            }
            else
            {
                msg.type = Chat;
                sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&serveraddr,
                       sizeof(serveraddr));
            }
        }
    }
    else
    {
        while (1) //收
        {
            if (recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL) < 0)
            {
                perror("recvfrom err.");
                return -1;
            }
            printf("%s said %s\n", msg.name, msg.text);
        }
    }
    close(sockfd);
    return 0;
}

到了这里,关于C语言实现--基于UDP的多人在线聊天室的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity工具,简单应用】Photon + PUN 2,做一个简单多人在线聊天室

    【Unity工具,简单学习】PUN 2,多人在线游戏开发,初步使用 需要有一定 UNITY 使用经验的开发者可以顺利阅读。 简单搭建一下大厅UI。 给 Laucher 节点一个 Launcher 脚本 Launcher 脚本如下,具体功能看注释 需要注意的是 PhotonNetwork.JoinOrCreateRoom(RoomName, new RoomOptions() { MaxPlayers = ma

    2024年02月08日
    浏览(36)
  • 基于Python web的多人聊天室

              本文介绍了基于即时通讯的Python实现web版多人聊天室的设计和实现。这个系统利用了多种先进的技术,如Django、Channels、WebSocket,来实现即时通信,并利用MySQL和Redis作为数据库,同时还采用了多种前端技术,如bootstrap、CSS、html和js,来提供出色的用户体验。该系

    2024年02月16日
    浏览(26)
  • 基于 SpringBoot+WebSocket 无DB实现在线聊天室(附源码)

    0.1 样例展示 0.2 源码地址 GitHub:https://github.com/ShiJieCloud/web-chat Gitee:https://gitee.com/suitbaby/web-chat GitCode:I’m Jie / web-chat · GitCode 1.1 HTTP 常用的 HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出

    2024年02月05日
    浏览(32)
  • Linux-Socket实现模拟群聊(多人聊天室)

    简单版本 服务端源码 客户端源码 服务器可以在特定的端口监听客户端的连接请求,若连接成功,服务器采用广播的形式向当前所有连接客户端发送该客户端登录成功消息多个客户端可以同时登录,在源码文件中可以配置最多群聊同时在线人数。服务端接收到客户端发送的群

    2024年02月10日
    浏览(77)
  • 【Linux】基于UDP协议的“聊天室”

    目录 预备知识 基本思路 服务端设计 重要接口详解 服务端核心代码 服务端运行代码 客户端设计 UDP协议(User Datagram Protocal用户数据报协议) 传输层协议 无连接 不可靠传输 面向数据报 如下是我们设计的一个简单的“聊天室”的大致框架图:         “聊天室”分为两个角

    2024年02月20日
    浏览(25)
  • WebSocket+Vue实现简易多人聊天室 以及 对异步调用的理解

    代码仓库:github   HTTP是不支持长连接的,WebSocket是一种通信协议,提供了在单一、长连接上进行全双工通信的方式。它被设计用于在Web浏览器和Web服务器之间实现,但也可以用于任何需要实时通信的应用程序。使用ws作为协议标识符,如果需要加密则使用wss作为协议标识符

    2024年01月17日
    浏览(43)
  • QT程序设计多人聊天室(基于QT、sqlite3、TCP/IP)

    目录 技术路线 效果展示 程序主体 sqoperator.h mylogin.h myenroll.h chatinterface.h tips.h myapp.h ******************* sqoperator.cpp mylogin.cpp myenroll.cpp chatinterface.cpp tips.cpp myapp.cpp main.cpp widget.h widget.cpp main.cpp QT程序设计、sqlite数据库调用、TCP/IP客户端与服务端的搭建 通过次程序代码,可以学习如

    2024年02月09日
    浏览(45)
  • 基于WebSocket的在线文字聊天室

    与Ajax不同,WebSocket可以使服务端主动向客户发送响应,本案例就是基于WebSocket的一个在线聊天室,不过功能比较简单,只能满足文字交流。演示如下。 案例学习于b站up主,链接 。这位up主讲的非常清楚,值得去学习。本文属于记录自我学习过程的文章。 项目目录下app.js 项

    2024年02月13日
    浏览(36)
  • 使用Linux系统IO多路复用中eopll创建基于TCP通信协议的多人聊天室

    一.1.搭建好TCP的通信模型 2.创建红黑树根节点 3.将套接字事件添加到红黑树中,使其被监听 4.当套接字事件发生,表示有客户端连接,将连接事件加入到红黑树节点当中 5.每当连接事件发生时,表示客户端发送信息到服务器 6.每当有事件准备就绪时,将对应的红黑树节点信息

    2024年02月13日
    浏览(30)
  • 基于SpringBoot+Vue+WebSocket的在线聊天室

    WebSocket 是一种在 Web 应用程序中实现双向通信的协议。它提供了一种持久连接,允许客户端和服务器之间进行实时数据传输,而无需进行频繁的请求和响应。 相对于传统的 HTTP 请求-响应模式,WebSocket 在客户端和服务器之间建立起一条长久的双向通信通道。这意味着服务器可

    2024年01月16日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包