UDP聊天室

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

1.头文件

/*===============================================
*   文件名称:UDP.h
*   创 建 者:crx    
*   创建日期:2023年09月3日
*   描    述:
================================================*/
#ifndef _UDP_H
#define _UDP_H

#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 <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

typedef struct node{            //链表节点保存用户地址结构体信息
    struct sockaddr_in caddr;  
    struct node *next;   
}Node,*Pnode;

typedef struct mesg{          //用户状态、姓名、消息
    char state;  
    char name[20];  
    char text[60];  
}Mesg;

enum state{         //状态:登录、转发、下线
    Login,  
    Relay,   
    Quit,   
};

//创建头节点
Pnode create_node();
//插入,登录
int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg);
//转发
void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg);
//删除,下线
int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg);

#endif

2.服务器

/*===============================================
 *   文件名称:UDPs.c
 *   创 建 者:crx     
 *   创建日期:2023年09月3日
 *   描    述:
 ================================================*/
#include "UDP.h"

int main(int argc, char *argv[])
{

    //1.创建套接字
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        return -1;
    }

    //2.绑定
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(8181);
    saddr.sin_addr.s_addr = INADDR_ANY;
    int bindfd = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
    if(-1 == bindfd)
    {
        perror("bind");
        return -1;
    }

    //3.准备保存客户端地址结构体,等待登录
    printf("等待登录....\n");
    struct sockaddr_in caddr;               
    socklen_t addrlen = sizeof(caddr);
    Mesg msg;

    //4.创建头节点
    Pnode p = create_node();    
    Pnode q = p;
    Pnode temp = p;

    while(1)
    {

        memset(&caddr,0,sizeof(caddr));  

        //5.接收用户登录信息
        recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&addrlen); 

       //6.根据用户状态执行对应操作

//msg.state = Login
//用户登录,链表插入用户信息
//判断链表是否为空,为空则插入用户
//链表不为空,判断是否是链表中已有用户,不是则插入用户信息
//转发登录消息给其他在线用户

        if(msg.state == Login)     
        {
            if(NULL == q->next)
            {           
                insert_node(p,caddr,msg);   
                strcpy(msg.text,"已登录!");
            }
            else
            {   
                temp = p->next;
                while(temp)
                {        
                    if(temp->caddr.sin_port == caddr.sin_port && temp->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr)
                        break;        
                    else
                        temp = temp->next;
                }
                if(NULL == temp)
                {
                    insert_node(p,caddr,msg);
                    strcpy(msg.text,"已登录!");
                    relay(sockfd,p,caddr,msg);
                }
            }
        }

//msg.state = Relay
//转发用户信息给其他在线用户

        if(msg.state == Relay)   
        {
            relay(sockfd,p,caddr,msg);
        }

//msg.state = Quit
//用户下线
//链表中删除用户信息
//转发用户下线信息给其他用户

        if(msg.state == Quit)        
        {
            delete_node(p,caddr,msg);
            strcpy(msg.text,"已下线");
            relay(sockfd,p,caddr,msg);
        }
    }

    return 0;
} 

//创建头节点
Pnode create_node()
{            
    Pnode p = (Pnode)malloc(sizeof(Node));
    if(NULL == p)
    {
        perror("malloc");
        return NULL;
    }
    p->next = NULL;
    return p;
}

//插入,登录
int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg)
{ 
    if(NULL == p)
    {
        return -1;
    }
    Pnode new = (Pnode)malloc(sizeof(Node));
    if(NULL == new)
    {
        perror("malloc");
        return -2;
    }
    new->next = p->next;
    p->next = new;
    new->caddr = caddr;
    printf("已登录!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));

    return 1;
}

//转发
void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg)        {
    while(p->next)
    {    
        p = p->next;
        if(p->caddr.sin_port == caddr.sin_port && p->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr)
        {
            continue;    
        }
        else
        {
            sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr)); 
        }
    }
}

//删除,下线
int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg)  
{
    if(NULL == p)
    {
        return -1;
    }
    while(p->next)
    {
        if(memcmp(&(p->next->caddr),&caddr,sizeof(caddr)) == 0)
        {
            Pnode q = p->next;
            p->next = q->next;
            free(q);
            break;
        }
        else
        {
            p = p->next;
        }
    }
    printf("已下线!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
}

3.客户端

/*===============================================
 *   文件名称:UDPc.c
 *   创 建 者:crx     
 *   创建日期:2023年09月3日
 *   描    述:
 ================================================*/
#include "UDP.h"

int main(int argc, char *argv[])
{
    //1.创建套接字
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(-1 == sockfd)
    {
        perror("socket");
        return -1;
    }

    //2.服务器地址
    struct sockaddr_in saddr;   
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(8181);
    saddr.sin_addr.s_addr = inet_addr("192.168.17.225");

    //3.创建用户
    Mesg msg;    

    //4.运行后触发msg.state = Login
    //登录填写用户名
    //发送给服务器登录信息转发登录消息操作
    printf("登录\n");   
    msg.state = Login;
    printf("请输入用户名:\n");
    fgets(msg.name,20,stdin);
    printf("******************************************\n");
    if(msg.name[strlen(msg.name)-1] == '\n')
        msg.name[strlen(msg.name) -1] = '\0';

    //发送用户登录消息
    if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr))) 
    {
        perror("sendto");
        return -1;
    }
   
    //5.创建子进程
    pid_t pid = fork();

    //6.子进程循环接收其他用户消息并打印发送人及信息
    if(pid == 0)  
    {
        while(1)
        {
            socklen_t addrlen = sizeof(saddr);
            recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,&addrlen);
            printf("~%s~ : %s\n",msg.name,msg.text);
        }
    } 
    else
    {
        //7.父进程获取用户终端输入到用户消息中
        while(1)
        {
            fgets(msg.text,sizeof(msg.text),stdin);    
            if(msg.text[strlen(msg.text)-1] == '\n')
                msg.text[strlen(msg.text) -1] = '\0';

         //8.处理终端输入

//终端输入Quit则触发msg.state = Quit
//发送给服务器下线信息执行对应操作
//使用SIGKILL强制结束进程

            if(strcmp(msg.text,"Quit") == 0)  
            {
                msg.state = Quit;
                if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr)))
                {
                    perror("sendto");
                    return -1;
                }
                kill(pid,SIGKILL); 
                wait(NULL);
                exit(0);
            }
//终端输入不是Quit则触发msg.state = Relay
//发送给服务端执行转发操作
            
            else
            {
                msg.state = Relay;  
            }
            if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr)))
            {
                perror("sendto");
                return -1;
            }
        }
    }
    close(sockfd);

    return 0;
}

4.makefile

all:UDPs UDPc
UDPs:UDPs.c
	gcc  UDPs.c -o UDPs
UDPc:UDPc.c
	gcc  UDPc.c -o UDPc
clean:
	rm UDPs UDPc

5.结果

UDP聊天室,udp,网络协议,网络文章来源地址https://www.toymoban.com/news/detail-693834.html

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

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

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

相关文章

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

    UDP(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。 数据报格式套接字 SOCK_DGRAM 采用UDP只管发送数据而不去验证发送数据的正确性,不论传输是否被接收,数据流是否有丢失,都不再重新发

    2024年02月08日
    浏览(57)
  • Linux 基本语句_16_Udp网络聊天室

    服务端代码: 客户端代码: 总体效果是客户上线状态、退出状态、发送的消息都能通过广播,将信息发送给所有在线客户端,服务端能接收并显示所有客户端发送的消息,且也具备广播能力 服务端: 服务端创建了一个链表,这个链表中的每个节点是专用于储存客户端的ip地

    2024年02月04日
    浏览(42)
  • 计算机网络 TCP/UDP程序开发网络聊天室

    TCP/UDP程序开发 开发TCP/UDP协议应用程序,掌握网络应用程序的工作原理。通过该实验,深入理解UDP和TCP协议的异同点,了解网络协议的工作过程,学会网络通信编程的基本方法,能够编制网络应用程序。 (1)了解和掌握“基于UDP-面向无连接的应用程序/基于TCP-面向连接的

    2024年02月05日
    浏览(89)
  • 【网络编程】UDP简单实现翻译软件与网络聊天室

    在上一章【网络编程】demo版UDP网络服务器实现实现了客户端和服务端之间的数据的发送与接收,上一章我们是直接让服务端把接收到的数据打印出来。 但是服务端并不是只接收到数据就完了,它还要 处理任务 。 所以我们可以在服务端设置一个回调函数: 用来处理接收到的

    2024年02月05日
    浏览(80)
  • 【嵌入式学习】网络通信基础-项目篇:简单UDP聊天室

    源码已在GitHub开源:0clock/LearnEmbed-projects/chat 客户端功能: 上线发送登录的用户名[yes] 发送消息和接收消息[yes] quit退出 服务器端功能: 统计用户上线信息,放入链表中[yes] 接收用户信息并给其他用户发送消息[yes] 服务器也支持给所有用户群发消息[yes] 接收下线提醒

    2024年01月25日
    浏览(64)
  • 【网络编程】利用套接字实现一个简单的网络通信(UDP实现聊天室 附上源码)

    源IP地址(Source IP Address): 源IP地址是数据包发送方(或数据流出发点)的唯一标识符。它用于在互联网或本地网络中定位发送数据包的设备或主机。源IP地址是数据包的出发点,即数据从这个地址开始传送,向目的IP地址指示的设备发送。 在TCP/IP协议中,源IP地址通常由发

    2024年02月14日
    浏览(86)
  • UDP聊天室

    1.头文件 2.服务器 3.客户端 4.makefile 5.结果

    2024年02月10日
    浏览(48)
  • C语言实现--基于UDP的多人在线聊天室

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

    2024年02月04日
    浏览(64)
  • UDP套接字的通信(实现英汉互译/程序替换/多线程聊天室/Windows与Linux通信)

    我们在客户端发英文,服务端做翻译工作,让翻译好的中文再次发给我们的客户端,然后打印出来。 翻译的操作 创建一个txt文件里面包含英汉互译的数据 dict.txt 对txt中的数据进行操作 分割函数 将英汉通过冒号分开。 将文件数据插入map里面 重新加载文件 通过捕捉2号(ctrl

    2024年02月11日
    浏览(38)
  • 基于TCP协议的聊天室详细教学(C++)

    服务器只转发消息不参到信息交流中 客户端输入用户名后默认进入群聊模式,输入“获取用户列表”可以获取在线用户用户名列表,如果需要私聊某一个用户需要输入“私聊+用户名”可进入私聊模式,输入“退出私聊”可退出私聊重新进入群聊模式。 基本群聊展示 获取用户

    2024年02月08日
    浏览(59)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包