首页 > 其他分享 >udt聊天室

udt聊天室

时间:2024-09-12 11:52:33浏览次数:11  
标签:聊天室 struct udt int len cdata sockfd data

创建一个简单的udp聊天室

服务器代码思路:

  1. 初始化

    • 创建UDP套接字。
    • 配置服务器的IP和端口号,并绑定套接字到这个地址。
  2. 数据接收和处理

    • 使用循环接收客户端发来的消息。recvfrom()
    • 解析消息类型(如登录、发送、下线)和内容。
  3. 广播消息

    • 对于聊天消息,将其广播给所有连接的客户端。
    • 对于登录和下线消息,通知其他客户端有新用户上线或某用户下线。
  4. 客户端管理

    • 维护一个客户端列表或字典,用于跟踪在线客户端的地址和状态。
    • 更新客户端列表以反映登录和下线事件。
  5. 清理和关闭

    • 在服务器关闭时,适当清理资源并关闭套接字。

服务器代码:

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>
#include <pthread.h>

typedef struct linklist
{ //创建存储客户端ip、端口号的链表
    struct sockaddr_in addr;
    struct linklist *next;
} l_node, *l_pnode;

typedef struct sockt_data
{                   //创建收发的信息结构体
    char name[64];  //名字
    char type[8];   //消息类别
    char text[128]; //信息内容
} data_t;

typedef struct Sock
{ //创建存储服务器发送数据的信息结构体
    struct sockaddr_in caddr;
    data_t cdata; //发送消息结构体
    int sockfd;   //套接字
} sock_t;

l_pnode create();                                              //创建链表节点
void login(int sockfd, data_t data, struct sockaddr_in saddr); //登录
void line(int sockfd, data_t data, struct sockaddr_in saddr);  //发送和下线
void *func(void *arg);                                         //子线程

l_pnode S; //开辟一个全局变量的链表

int main(int argc, char *argv[])
{
//  1、创建套接字 -- socket 
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    // 2、绑定IP地址和端口号 -- bind
    struct sockaddr_in saddr, caddr;

    caddr.sin_family = AF_INET;
    caddr.sin_port = htons(8888); //将主机字节序转换为网络字节序再赋值
    caddr.sin_addr.s_addr = htons(INADDR_ANY);

    int s_len = sizeof(saddr);
    bind(sockfd, (struct sockaddr *)&caddr, s_len);
    // 3、发送接送数据 
    data_t sdata = {0, 0, 0}; //定义接送数据结构体
    int d_len = sizeof(sdata);
    int c_len = sizeof(caddr); //计算服务器地址结构的大小
    memset(&saddr, 0, c_len);  //清空接收地址结构

    S = (l_pnode)malloc(sizeof(l_node)); //初始化链表
    S->next = NULL;

    sock_t csock;          //创建子线程所需结构体
    csock.sockfd = sockfd; //传递套接字

    pthread_t thread;
    pthread_create(&thread, NULL, func, &csock); //创建子线程

    while (1)
    {
        memset(&sdata, 0, d_len);                                              //清空接送到的数据
        recvfrom(sockfd, &sdata, d_len, 0, (struct sockaddr *)&saddr, &c_len); //接送来自客户端的消息
        printf("%s:%s\n", sdata.name, sdata.text);                             //在服务器中显示接送到的消息
        if (strcmp(sdata.type, "login") == 0)                                  //判断接受消息内型
            login(sockfd, sdata, saddr);                                       //上线操作
        else
            line(sockfd, sdata, saddr); //聊天、下线操作
    }
//   4、关闭套接字 
    close(sockfd);
    return 0;
}
//  子线程 
void *func(void *arg) //线程处理函数
{
    sock_t csock = *(sock_t *)arg;     //获取主函数中传递过来的内容
    strcpy(csock.cdata.type, "login"); //设置要发送的结构图
    strcpy(csock.cdata.name, "服务器");
    while (1)
    {
        memset(&csock.cdata.text, 0, 128);                     //清空输入进来的内容
        fgets(csock.cdata.text, 64, stdin);                    //获取输入进来的内容
        csock.cdata.text[strlen(csock.cdata.text) - 1] = '\0'; //删除获取进来的回车'\n'
        line(csock.sockfd, csock.cdata, csock.caddr);          //向所有在线的客户端发送入进来的内容
    }
}
//  上线 
void login(int sockfd, data_t data, struct sockaddr_in saddr) //登录
{
    int d_len = sizeof(data);
    int s_len = sizeof(saddr);
    l_pnode new = create(); //创建新节点
    new->addr = saddr;      //传递接送到的客户端IP、端口号
    new->next = NULL;
    l_pnode N = create();
    N = S;
    while (N->next) //尾插并发送给其他客户端
    {
        N = N->next;
        sendto(sockfd, &data, d_len, 0, (struct sockaddr *)&N->addr, s_len); //发送给除该客户信息的其他客户
    }
    N->next = new;
}
//  聊天、下线 
void line(int sockfd, data_t data, struct sockaddr_in saddr) //聊天、下线
{
    int d_len = sizeof(data);
    int s_len = sizeof(saddr);
    l_pnode N = create();
    N = S;
    while (N->next)
    {
        if ((N->next->addr.sin_addr.s_addr == saddr.sin_addr.s_addr) && (N->next->addr.sin_port == saddr.sin_port)) //判断是否存在该客户端数据
        {
            if (strcmp(data.type, "line") == 0) //下线,删除用户信息
            {
                l_pnode Q = N->next;
                N->next = Q->next; //连线
                free(Q);           //释放空间
                Q = NULL;
            }
            if (strcmp(data.type, "send_t") == 0) //聊天,跳过用户
                N = N->next;
        }
        if (N->next != NULL) //判断是否到尾节点
        {
            N = N->next;
            sendto(sockfd, &data, d_len, 0, (struct sockaddr *)&N->addr, s_len); //发送给除该客户信息的其他客户
        }
        else
            break;
    }
}
//  创建链表新节点
l_pnode create()
{
    l_pnode S = (l_pnode)malloc(sizeof(l_node));
    S->next = NULL;
    return S;
}

客户端代码思路:

  1. 初始化和创建套接字:在函数中,创建一个UDP套接字,并配置客户端的IP地址和端口。main

  2. 进程创建:使用创建一个子进程。子进程负责读取用户输入的用户名和消息,并处理登录、发送和下线操作。fork()

  3. 父进程接收消息:父进程不断接收来自服务器的消息,并在控制台显示。

  4. 登录、发送和下线功能

    • login():向服务器发送登录消息。
    • send_t():发送聊天消息。
    • line():发送下线消息并退出子进程。
  5. 信号处理:使用处理子进程结束的信号,确保子进程资源得到清理。signal(SIGCHLD, mysignal)

客户端代码:


#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
typedef struct sockt_data
{
    char name[64];//用户户名
    char type[8];//消息类别
    char text[128];//消息内容
} data_t;

void mysignal(int arg) //回收子进程
{
    wait(NULL);
    exit(0);
}

void login(int sockfd, data_t cdata, struct sockaddr_in caddr); //登录
void send_t(int sockfd, data_t data, struct sockaddr_in saddr); //发送信息
void line(int sockfd, data_t cdata, struct sockaddr_in caddr);  //下线

int main(int argc, char *argv[])
{
    if (argc != 2)
        printf("请正确输入: ./client IP号\n");
    //  1、创建套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    // 2、绑定IP地址和端口号 -- bind
    struct sockaddr_in saddr, caddr;
    caddr.sin_family = AF_INET;
    caddr.sin_port = htons(8888); //将主机字节序转换为网络字节序再赋值
    caddr.sin_addr.s_addr = inet_addr(argv[1]);

    int s_len = sizeof(saddr);
    //  3、发送接送数据
    data_t cdata = {0, 0, 0}, sdata = {0, 0, 0}; //定义收发数据结构体

    int d_len = sizeof(cdata); //计算数据结构体长度

    memset(&saddr, 0, s_len);  //清空接收地址结构
    memset(&cdata, 0, d_len);  //清空接收地址结构
    signal(SIGCHLD, mysignal); //捕获子进程释放信号

    pid_t pid = fork(); //创建线程
    if (0 == pid)       //子线程
    {
        printf("请输入你的用户名--->");
        fgets(cdata.name, 64, stdin);              //获取输入进来的名字
        cdata.name[strlen(cdata.name) - 1] = '\0'; //删除获取进来的回车'\n'
        login(sockfd, cdata, caddr);               //登录

        while (1)
        {
            fgets(cdata.text, 64, stdin);              //获取输入进来的内容
            cdata.text[strlen(cdata.text) - 1] = '\0'; //删除获取进来的回车'\n'
            if (strcmp(cdata.text, "line!!!") == 0)    //判断是否结束聊天
                line(sockfd, cdata, caddr);            //下线
            send_t(sockfd, cdata, caddr);              //聊天
        }
    }

    while (1)
    {
        memset(&sdata, 0, d_len); //清空接送到的数据
        recvfrom(sockfd, &sdata, d_len, 0, (struct sockaddr *)&saddr, &s_len);
        if (strcmp(sdata.type, "send_t") == 0) //在客户端中显示接送到的消息
            printf("%s:%s\n", sdata.name, sdata.text);
        else
            printf("%s-->%s\n", sdata.name, sdata.text);
    }
    //  4、关闭套接字
    close(sockfd);
    return 0;
}
// 登录
void login(int sockfd, data_t cdata, struct sockaddr_in caddr) //登录
{
    int d_len = sizeof(cdata);
    int s_len = sizeof(caddr);
    strcpy(cdata.type, "login");
    strcpy(cdata.text, "上线了");
    sendto(sockfd, &cdata, d_len, 0, (struct sockaddr *)&caddr, s_len);
}
//    下线
void line(int sockfd, data_t cdata, struct sockaddr_in caddr) //下线
{
    int d_len = sizeof(cdata);
    int s_len = sizeof(caddr);
    strcpy(cdata.type, "line");
    strcpy(cdata.text, "下线了");
    sendto(sockfd, &cdata, d_len, 0, (struct sockaddr *)&caddr, s_len);
    exit(0);
}
// 聊天
void send_t(int sockfd, data_t cdata, struct sockaddr_in caddr) //发送信息
{
    int ret = 0;
    int d_len = sizeof(cdata);
    int s_len = sizeof(caddr);
    strcpy(cdata.type, "send_t");
    ret = sendto(sockfd, &cdata, d_len, 0, (struct sockaddr *)&caddr, s_len);
}

标签:聊天室,struct,udt,int,len,cdata,sockfd,data
From: https://blog.csdn.net/weixin_63207763/article/details/142171620

相关文章

  • Applications of UDTL to Intelligent Fault Diagnosis: A Survey and Comparative St
    文章目录摘要一、引言二、背景和定义A.UDTL定义B.基于UDTL的IFD分类C.基于UDTL的IFD动机D.主干结构三、LABEL-CONSISTENTUDTLA.基于网络的UDTLB.基于实例化的UDTLC.基于映射的UDTLD.基于对抗性的IFD四.LABEL-INCONSISTENTUDTLA.PartialUDTLB.OpenSetUDTLC.Uni......
  • Vue2 - 详细实现聊天室IM即时通讯及聊天界面,支持发送图片视频、消息已读未读等,集成mqt
    前言如果您需要Vue3版本,请访问在vue2|nuxt2项目开发中,详解手机移动端H5网页在线1v1聊天功能(仿腾讯云IM功能),技术栈为MQTT通讯协议+后端Node服务端+数据库设计+vue前端聊天界面,超详细前后端完整流程及示例源代码,vue2聊天即时通讯IM实时接收和发送消息,可发送文字、图......
  • UDT(一):概览
    1.参考链接官网https://udt.sourceforge.io/谷博士对UDT的简单介绍https://udt.sourceforge.io/doc/udt-2009.ppt获取UDT源码https://sourceforge.net/projects/udt/files/udt/4.11/udt.sdk.4.11.tar.gz/download?use_mirror=pilotfiberUDT讨论贴https://sour......
  • websocket基础 以及 搭建在线聊天室
    一,什么是websocketWebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的Websocket是一个持久化的协议二,websocket的原理websocket约定了一个通信的规范,通过一......
  • 实现网络聊天室(UDP)
    项目需求:如果有用户登录,其他用户可以收到这个人的登录信息如果有人发送信息,其他用户可以收到这个人的群聊信息如果有人下线,其他用户可以收到这个人的下线信息服务器可以发送系统信息服务器端:#include<myhead.h>structsockaddr_inserveraddr,caddr;enumtype_t//枚举{......
  • springboot+vue前后端分离项目-项目搭建19-ElementUI图标+聊天室
    一、ElementUI图标按照官网这两步,注册所有图标,然后就能直接使用 1.安装后在vue/package.json里能看到包 2.注册所有图标 3.点击自动复制,直接就能使用 4.效果: ......
  • NIO聊天室
    SocketChannel和ServerSocketChannelServerSocketChannel用于创建服务器端套接字,而SocketChannel用于创建客户端套接字。它们都支持阻塞和非阻塞模式,通过设置其blocking属性来切换。阻塞模式下,读/写操作会一直阻塞直到完成,而非阻塞模式下,读/写操作会立即返回。阻塞模式:......
  • 【Unity/网络】Unity和内网穿透的网络测试 —— 以聊天室为例
    这两天在做那个CodeMonky的胡闹厨房的案例,一直困扰我的是关于Lobby和Relay的相关网络服务,需要挂加速器并且延迟不低,所以我一直在寻找一些其他替代方案,想起来之前做一个UEC++的网络枪战时做过一个内网穿透的方法,所以在Unity中也采用这个方案,但中间怎么改IP和端口都没法连接成......
  • TCP/UDP网络聊天室
        本博客仅对网络聊天室项目进行分享,仅供学习讨论使用,欢迎大家讨论。UDP网络聊天室项目要求        利用UDP协议,实现一套聊天室软件。服务器端记录客户端的地址,客户端发送消息后,服务器群发给各个客户端软件,服务器也可以自己发送通知给所有客户端。  ......
  • 坐牢第二十七天(聊天室)
    基于UDP的网络聊天室一.项目需求:1.如果有用户登录,其他用户可以收到这个人的登录信息2.如果有人发送信息,其他用户可以收到这个人的群聊信息3.如果有人下线,其他用户可以收到这个人的下线信息4.服务器可以发送系统信息二.代码 udp.h#ifndefUDP_H#defineUDP_H#includ......