【Linux网络编程】基于UDP实现多人聊天室

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

一、UDP的概念

1.1 UDP

UDP(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。

数据报格式套接字SOCK_DGRAM

1.2 UDP特点

采用UDP只管发送数据而不去验证发送数据的正确性,不论传输是否被接收,数据流是否有丢失,都不再重新发送,特征如下:

  1. 强调快速传输而非传输顺序;
  2. 传输的数据可能丢失也可能损毁;
  3. 限制每次传输的数据大小;
  4. 数据的发送和接收是并发的。

二. 采用UDP实现多人聊天室原因

数据报套接字采用的是UDP(User Datagram Protocol)协议,本次聊天室采用UDP协议虽然可能会导致数据丢失,但是聊天并不去强调内容的正确性,而应该强调实时性和并发,并且数据丢失只是小概率事件。

三、多人聊天室项目功能

  1. 当有用户加入群聊上线时,将登录消息发给在线的所有人
  2. 当有用户在线发送消息时,将消息发给在线的所有人
  3. 当有用户退出群聊时,将用户退出消息发给在线的所有人
  4. 服务器可以发送系统公告消息

四、实现多人聊天室项目流程分析

4.1 前期准备

4.1.1 定义结构体

由于客户端给服务器发送的数据内容较多,所以需要定义结构体来发送:

typedef struct
{
    char code; //操作码 'L' 登录  'C' 群聊  'Q' 退出
    char name[32];
    char txt[128];
} msg_t;

code相当于一个协议,用来确定将要进行的操作。
code为 ‘L’ 登录 ‘C’ 群聊 ‘Q’ 退出

name[32]用来保存登录用户名;

txt[128]用来保存发送的信息

4.1.2 定义链表

服务器要给在线的所有客户端发送数据,需要将每一个客户端的信息保存,使用链表来保。

typedef struct _NODE
{
    struct sockaddr_in c_addr;//数据域
    struct _NODE *next;//指针域
} node_t;

数据域:客户端的网络信息结构体;

指针域:保存下一个结点的地址;

4.2 多人聊天室服务器

服务器既可以发送系统信息,又可以接收客户端信息并处理,可以使用多进程或者多线程
本次使用多进程实现多人聊天室服务器。

pid_t pid;
pid = fork();
if (pid == -1)
{
    //创建错误
}
else if (pid == 0)
{
    //子进程
    //接受数据并处理
}
else if (pid > 0)
{
    //父进程
    //发系统消息
}

4.2.1 接收客户端发来的消息并进行处理

子进程循环接收客户端发来的消息,通过switch判断code所存的协议,执行特定的功能函数。

  1. 登录操作函数
  2. 群聊操作函数
  3. 退出操作函数

4.2.2 聊天室群公告功能

将父进程视为一个客户端,向子进程发送消息给所有在线的用户。

4.3 多人聊天室客户端

客户端登录之后,为了实现一边发送数据一边接收数据,可以使用多进程或者多线程;
本次使用多进程实现多人聊天室客户端。代码框架同上。

4.3.1 接收服务器发来的消息并进行处理

子进程循环接受服务器发来的消息,并将其打印在终端上。

4.3.2 向服务器发送消息

父进程循环向服务器发送群聊的消息,如果当消息为 “quit” 时进行用户退出群聊操作。

五、多人聊天室流程图

5.1 服务器流程图

【Linux网络编程】基于UDP实现多人聊天室

5.2 客户端流程图

【Linux网络编程】基于UDP实现多人聊天室

六、根据多人聊天室流程模块化进行代码实现

宏定义打印错误信息,进行健壮性判断。

#define PRINT_ERR(msg)                                  \
do                                                      \
{                                                       \
    printf("%s,%d,%s\n", __FILE__, __LINE__, __func__); \
    perror(msg);                                        \
    exit(-1);                                           \
} while (0)

入参合理性判断 可执行文件 ip地址 端口号

if (argc != 3)
{
    printf("age:%s ip port\n", argv[0]);
    return -1;
}

6.1 服务器代码实现

6.1.1 创建套接字

int sockfd;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
    PRINT_ERR("socket error");
}

6.1.2 创建服务器网络信息结构体

struct sockaddr_in serviceaddr;
memset(&serviceaddr, 0, sizeof(serviceaddr));
serviceaddr.sin_family = AF_INET;
serviceaddr.sin_addr.s_addr = inet_addr(argv[1]);
serviceaddr.sin_port = htons(atoi(argv[2]));
socklen_t serviceaddr_len = sizeof(serviceaddr);

6.1.3 将服务器网络信息结构体与套接字绑定

if (bind(sockfd, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1)
{
    PRINT_ERR("bind error");
}

6.1.4 创建客户端网络信息结构体

struct sockaddr_in clientaddr;
memset(&clientaddr, 0, sizeof(clientaddr));
socklen_t clientaddr_len = sizeof(clientaddr);

6.1.5 子进程内部实现代码

  1. 使用链表头节点函数,定义链表头节点
//创建链表头节点函数
void creat_link(node_t **head)
{
    *head = (node_t *)malloc(sizeof(node_t));
}

//定义链表头节点
node_t *phead = NULL;
creat_link(&phead);
phead->next = NULL;
  1. 循环接受客户端发来的信息并通过switch进行判断执行哪个功能函数
while (1)
{
    memset(&msg, 0, sizeof(msg));//清空操作
    memset(&clientaddr, 0, sizeof(clientaddr));//清空操作
    if ((recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&clientaddr, &clientaddr_len)) == -1)
    {
        PRINT_ERR("recvfrom error");
    }
    printf("%8s : [%s]\n", msg.name, msg.txt);
    switch (msg.code)
    {
    case 'L':
        do_register(sockfd, msg, clientaddr, phead);
        break;
    case 'C':
        do_group_chat(sockfd, msg, clientaddr, phead);
        break;
    case 'Q':
        quit_group_chat(sockfd, msg, clientaddr, phead);
        break;
    }
}
  1. 注册操作函数

注册时,遍历链表将用户登录信息发给所以在线的用户,并将自己的客户端网络信息结构体头插进入链表中。

int do_register(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{
    //遍历链表将登录信息发送给所以人
    node_t *p = phead;
    while (p->next != NULL)
    {
        p = p->next;
        if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
        {
            PRINT_ERR("recvfrom error");
        }
    }
    //将登录的客户端信息插入保存在链表
    //头插
    //定义一个新的指针保存客户端信息
    node_t *newp = NULL;
    creat_link(&newp);
    newp->c_addr = clientaddr;
    newp->next = phead->next;
    phead->next = newp;
    return 0;
}
  1. 群聊操作函数

群聊时通过遍历,将txt中的信息发送给处了自己以外的所有在线用户

int do_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{
    //遍历链表,将消息发给除自己之外的所有人
    node_t *p = phead;
    while (p->next != NULL)
    {
        p = p->next;
        //判断链表客户端信息是否是自己
        //是自己就不发送
        if (memcmp(&(p->c_addr), &clientaddr, sizeof(clientaddr)))
        {
            if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
            {
                PRINT_ERR("recvfrom error");
            }
        }
    }
    return 0;
}
  1. 退出操作函数

退出时,遍历链表将退出信息发送给除自己以外的所有在线用户,并将自己的客户端网络信息结构体在链表中删除。

int quit_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{
    node_t *p = phead;

    while (p->next != NULL)
    {
        //判断链表客户端信息是否是自己
        //是自己就不发送并且将自己的客户端信息在链表内删除
        if (memcmp(&(p->next->c_addr), &clientaddr, sizeof(clientaddr)))
        {
            p = p->next;
            if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
            {
                PRINT_ERR("recvfrom error");
            }
        }
        else
        {
            node_t *pnew;
            pnew = p->next;
            p->next = pnew->next;
            pnew->next = NULL;
            free(pnew);
            pnew = NULL;
        }
    }
    return 0;
}

6.1.6 父进程内部实现代码

父进程视为一个客户端,向子进程发送消息,遍历链表给所有在线的用户。

msg.code='C';
strcpy(msg.name,"server");
while(1)
{
    fgets(msg.txt,128,stdin);
    msg.txt[strlen(msg.txt)-1]='\0';
    if(sendto(sockfd,&msg,sizeof(msg_t),0,(struct sockaddr *)&serviceaddr,serviceaddr_len)==-1)
    {
        PRINT_ERR("sendto error");
    }
}

代码结束前,在最后记得关闭套接字close(sockfd);

6.2 客户端代码实现

6.2.1 前两部与服务器一样

6.2.2 给服务器发送登录数据包

msg_t msg;
memset(&msg, 0, sizeof(msg_t));
msg.code = 'L';
printf("请输入用户名:");
fgets(msg.name, 32, stdin);
msg.name[strlen(msg.name) - 1] = '\0';

strcpy(msg.txt, "加入群聊");
if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1)
{
    PRINT_ERR("sendto error");
}

6.2.3 子进程内部实现代码

循环接收服务器发来的数据,并将其打印在终端上。

while (1)
{
    //每次循环前将msg置零
    memset(&msg, 0, sizeof(msg));
    //接受服务器发过来的信息并打印到终端上
    if (recvfrom(sockfd, &msg, sizeof(msg_t), 0, NULL, NULL) == -1)
    {
        PRINT_ERR("recvfrom error");
    }
    printf("%8s:[%s]\n", msg.name, msg.txt);
}

6.2.4 父进程内部实现代码

先将协议设置为群聊,将终端输入的数据发送给服务器,当终端输入"quit"时,将协议设置为退出,并将退出群聊发送给服务器。
如果退出向终端输入"quit"时,退出循环。

while (1)
{   
    //memset会把name清除
    msg.code = 'C';
    fgets(msg.txt, 128, stdin);
    msg.txt[strlen(msg.txt) - 1] = '\0';
    if (strcmp(msg.txt, "quit") == 0)
    {
        msg.code = 'Q';
        strcpy(msg.txt, "退出群聊");
    }
    if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1)
    {
        PRINT_ERR("sendto error");
    }
    if (strcmp(msg.txt, "退出群聊") == 0)
    {
        break;
    }
}

6.2.5 退出程序

给子进程发送杀死信号,等待回收子进程,关闭套接字。

kill(pid,SIGKILL);
wait(NULL);
close(sockfd);

七、结果展示和总结

7.1 结果展示

用户之间聊天成功
【Linux网络编程】基于UDP实现多人聊天室
系统发送公告成功
【Linux网络编程】基于UDP实现多人聊天室
退出群聊成功
【Linux网络编程】基于UDP实现多人聊天室
成功实现基于UDP的多人聊天室。

7.2 缺点与不足

没有对客户端断连采取更为健壮的处理,应该再客户端捕获一下客户端因为ctrl+c而结束的信号,在捕获之后发送数据包给服务器,让服务器对客户端退出行为,做出删除保存客户信息结构体的行为。还有就是没有添加数据库的使用。

7.3 总结

整体项目并不复杂,只需要想清楚service和client分别需要做什么事。画好流程图,就会很清晰的将思路缕顺。从而只需要模块化的完成相应代码即可。

server为了保存每次连入进来的client信息,使用了链表,对链表的操作就是简单的插入,删除操作。

这算是最近学习中实现的一个稍微综合一点的项目,虽然不多,却也有所收获,便发布一篇帖子去记录,代码中可能有许多不规范的地方,逻辑可能并不严谨,还请各位不吝赐教。文章来源地址https://www.toymoban.com/news/detail-479108.html

八、UDP实现多人聊天室服务器源代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
//宏定义打印错误信息
#define PRINT_ERR(msg)                                      \
    do                                                      \
    {                                                       \
        printf("%s,%d,%s\n", __FILE__, __LINE__, __func__); \
        perror(msg);                                        \
        exit(-1);                                           \
    } while (0)

typedef struct
{
    char code; //操作码 'L' 登录  'C' 群聊  'Q' 退出
    char name[32];
    char txt[128];
} msg_t;
//链表结构体
typedef struct _NODE
{
    struct sockaddr_in c_addr;
    struct _NODE *next;
} node_t;

void creat_link(node_t **head);
int do_register(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead);
int do_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead);
int quit_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead);

int main(int argc, const char *argv[])
{
    //入参合理性判断
    if (argc != 3)
    {
        printf("age:%s ip port\n", argv[0]);
        return -1;
    }
    //创建套接字
    int sockfd;
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        PRINT_ERR("socket error");
    }
    //创建服务器网络信息结构体
    struct sockaddr_in serviceaddr;
    memset(&serviceaddr, 0, sizeof(serviceaddr));
    serviceaddr.sin_family = AF_INET;
    serviceaddr.sin_addr.s_addr = inet_addr(argv[1]);
    serviceaddr.sin_port = htons(atoi(argv[2]));
    socklen_t serviceaddr_len = sizeof(serviceaddr);
    //将服务器网络信息结构体与套接字绑定
    if (bind(sockfd, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1)
    {
        PRINT_ERR("bind error");
    }
    //创建客户端网络信息结构体
    struct sockaddr_in clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    socklen_t clientaddr_len = sizeof(clientaddr);
    msg_t msg;
    //创建父子进程
    pid_t pid;
    pid = fork();
    if (pid == -1)
    {
        PRINT_ERR("fork error");
    }
    else if (pid == 0)
    {
        //子进程
        //接受数据并处理

        //定义链表头节点
        node_t *phead = NULL;
        creat_link(&phead);
        phead->next = NULL;

        while (1)
        {
            memset(&msg, 0, sizeof(msg));
            memset(&clientaddr, 0, sizeof(clientaddr));
            if ((recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&clientaddr, &clientaddr_len)) == -1)
            {
                PRINT_ERR("recvfrom error");
            }
            printf("%8s : [%s]\n", msg.name, msg.txt);
            switch (msg.code)
            {
            case 'L':
                do_register(sockfd, msg, clientaddr, phead);
                break;
            case 'C':
                do_group_chat(sockfd, msg, clientaddr, phead);
                break;
            case 'Q':
                quit_group_chat(sockfd, msg, clientaddr, phead);
                break;
            }
        }
    }
    else if (pid > 0)
    {
        //父进程
        //发系统消息
        msg.code='C';
        strcpy(msg.name,"server");
        while(1)
        {
            fgets(msg.txt,128,stdin);
            msg.txt[strlen(msg.txt)-1]='\0';
            if(sendto(sockfd,&msg,sizeof(msg_t),0,(struct sockaddr *)&serviceaddr,serviceaddr_len)==-1)
            {
                PRINT_ERR("sendto error");
            }
        }
    }
    close(sockfd);
    return 0;
}
//创建链表头节点函数
void creat_link(node_t **head)
{
    *head = (node_t *)malloc(sizeof(node_t));
}
//登录操作
int do_register(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{
    //遍历链表将登录信息发送给所以人
    node_t *p = phead;
    while (p->next != NULL)
    {
        p = p->next;
        if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
        {
            PRINT_ERR("recvfrom error");
        }
    }
    //将登录的客户端信息插入保存在链表
    //头插
    //定义一个新的指针保存客户端信息
    node_t *newp = NULL;
    creat_link(&newp);
    newp->c_addr = clientaddr;
    newp->next = phead->next;
    phead->next = newp;
    return 0;
}

int do_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{
    //遍历链表,将消息发给除自己之外的所有人
    node_t *p = phead;
    while (p->next != NULL)
    {
        p = p->next;
        //判断链表客户端信息是否是自己
        //是自己就不发送
        if (memcmp(&(p->c_addr), &clientaddr, sizeof(clientaddr)))
        {
            if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
            {
                PRINT_ERR("recvfrom error");
            }
        }
    }
    return 0;
}
//退出群聊操作
int quit_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{
    node_t *p = phead;

    while (p->next != NULL)
    {
        //判断链表客户端信息是否是自己
        //是自己就不发送并且将自己的客户端信息在链表内删除
        if (memcmp(&(p->next->c_addr), &clientaddr, sizeof(clientaddr)))
        {
            p = p->next;
            if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1)
            {
                PRINT_ERR("recvfrom error");
            }
        }
        else
        {
            node_t *pnew;
            pnew = p->next;
            p->next = pnew->next;
            pnew->next = NULL;
            free(pnew);
            pnew = NULL;
        }
    }
    return 0;
}

九、UDP实现多人聊天室客户端源代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
//宏定义打印错误信息
#define PRINT_ERR(msg)                                      \
    do                                                      \
    {                                                       \
        printf("%s,%d,%s\n", __FILE__, __LINE__, __func__); \
        perror(msg);                                        \
        exit(-1);                                           \
    } while (0)

typedef struct
{
    char code; //操作码 'L' 登录  'C' 群聊  'Q' 退出
    char name[32];
    char txt[128];
} msg_t;

int main(int argc, const char *argv[])
{
    //入参合理性判断
    if (argc != 3)
    {
        printf("age:%s ip port\n", argv[0]);
        return -1;
    }
    //创建套接字
    int sockfd;
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        PRINT_ERR("socket error");
    }
    //创建服务器网络信息结构体
    struct sockaddr_in serviceaddr;
    memset(&serviceaddr, 0, sizeof(serviceaddr));
    serviceaddr.sin_family = AF_INET;
    serviceaddr.sin_addr.s_addr = inet_addr(argv[1]);
    serviceaddr.sin_port = htons(atoi(argv[2]));
    socklen_t serviceaddr_len = sizeof(serviceaddr);
    //给服务器发送登录数据包
    msg_t msg;
    memset(&msg, 0, sizeof(msg_t));
    msg.code = 'L';
    printf("请输入用户名:");
    fgets(msg.name, 32, stdin);
    msg.name[strlen(msg.name) - 1] = '\0';

    strcpy(msg.txt, "加入群聊");
    if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1)
    {
        PRINT_ERR("sendto error");
    }
    //创建父子进程
    pid_t pid;
    pid = fork();
    if (pid == -1)
    {
        PRINT_ERR("fork error");
    }
    else if (pid == 0)
    {
        //子进程
        //接受数据并处理
        while (1)
        {
            //每次循环前将msg置零
            memset(&msg, 0, sizeof(msg));
            //接受服务器发过来的信息并打印到终端上
            if (recvfrom(sockfd, &msg, sizeof(msg_t), 0, NULL, NULL) == -1)
            {
                PRINT_ERR("recvfrom error");
            }
            printf("%8s:[%s]\n", msg.name, msg.txt);
        }
    }
    else if (pid > 0)
    {
        //父进程
        //发送消息
        while (1)
        {   
            //memset会把name清除
            msg.code = 'C';
            fgets(msg.txt, 128, stdin);
            msg.txt[strlen(msg.txt) - 1] = '\0';
            if (strcmp(msg.txt, "quit") == 0)
            {
                msg.code = 'Q';
                strcpy(msg.txt, "退出群聊");
            }
            if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1)
            {
                PRINT_ERR("sendto error");
            }
            if (strcmp(msg.txt, "退出群聊") == 0)
            {
                break;
            }
        }
        kill(pid,SIGKILL);
        wait(NULL);
        close(sockfd);
    }
    return 0;
}

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

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

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

相关文章

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

    目录 实现功能 实现思想 实现代码(部分及详解) 服务端部分代码 客户端部分代码 实现效果 项目中出现的问题和解决方法 项目整体代码展示 代码优化思路 服务端代码 客户端代码 服务端可以同时连接多个客户端; 新的客户端连接服务端时,可以在服务端显示自己的名字并

    2024年02月04日
    浏览(64)
  • linux【网络编程】之UDP网络程序模拟实现

    本次实验是在腾讯云服务器上进行 做完这次实验,感受最深的就是函数接口方面的问题,我们先来介绍一下需要用到的接口。 2.1.1 socket创建网络通信套接字 2.1.2 bind:绑定Ip和端口号 2.1.3 sockaddr_in结构体 宏中的**##**是将两个字符串合并成一个新字符串,也就是将接收到的sa

    2024年02月03日
    浏览(49)
  • 基于UDP/TCP的网络通信编程实现

    红色是心中永不褪色的赤诚 操作系统为网络编程提供了 Socket api , Socket是基于TCP/IP协议的网络通信的基本单元, 基于Socket的网络程序开发就是 网络编程. 由于直接与应用层联系的是传输层, 所以针对应用层协议(TCP, UDP), Shocket提供了三种套接字, 分别是 流套接字(使用TCP) , 数据报

    2024年02月08日
    浏览(55)
  • 【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)

    在前一篇文章中,我们详细介绍了UDP协议和TCP协议的特点以及它们之间的异同点。 本文将延续上文内容,重点讨论简单的UDP网络程序模拟实现 。通过本文的学习,读者将能够深入了解UDP协议的实际应用,并掌握如何编写简单的UDP网络程序。让我们一起深入探讨UDP网络程序的

    2024年04月08日
    浏览(174)
  • Python多人聊天室-基于socket UDP协议

    使用Python编写的基于socket UDP通信的多功能即时聊天室,包含Tkinter编写的图形化聊天界面,功能包括有账号注册和登录,登录成功后可以查看在线用户,并和聊天室内的其他在线用户聊天,包含私聊和群发,能发送文字、表情包,以及文件等。 登录和注册 显示在线用户 群聊

    2024年02月11日
    浏览(58)
  • 【网络编程】基于UDP数据报实现回显服务器/客户端程序

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程的一点学习心得,欢迎大家在评论区交流讨论💌 前言 我们如果想让应用程序进行网络通信的话,就需要调用传

    2024年02月04日
    浏览(54)
  • 【Java网络编程】基于UDP-Socket 实现客户端、服务器通信

    ​ 哈喽,大家好~我是你们的老朋友: 保护小周ღ   本期为大家带来的是网络编程的 UDP Socket 套接字,基于 UDP协议的 Socket 实现客户端服务器通信 ,Socket 套接字可以理解为是,传输层给应用层提供的一组 API,如此程序,确定不来看看嘛~~ 本期收录于博主的专栏 : JavaEE_保

    2024年02月02日
    浏览(71)
  • Linux网络编程——UDP编程

    1、UDP通信协议,服务器端和客户端无需建立连接,只需要知道对方套接字的地址信息就可以发送数据 2、UDP通信流程图: 功能:创建套接字并返回套接字描述符 功能:将套接字与IP地址和端口号绑定 功能:发送数据 功能:接收数据 功能:关闭套接字 1、代码功能:两个进程

    2023年04月19日
    浏览(46)
  • 【Linux C | 网络编程】多播的概念、多播地址、UDP实现多播的C语言例子

    😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭 🤣本文内容🤣:🍭介绍多播的概念、多播地址、UDP实现广播的C语言例子 🍭 😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭

    2024年03月11日
    浏览(53)
  • 基于UDP实现的网络聊天室

    服务器: 客户端: 运行结果:

    2024年03月08日
    浏览(65)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包