udp聊天室

第一次写udp通信,没想到能这么快完成;

现在看来显得有些限制和臃肿,没有进行优化,不过确实能实现局域网内的聊天室功能;

一、服务器模块

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
typedef struct msg_t
{
    char name[128];
    char text[128];
}MSG_t;
typedef struct node
{
    union 
    {
        int len;
        char user_name[23];
    };
    struct sockaddr_in addr;
    struct node* next;
}node;
node*head_creat();
node*creat_node(char*name,sa_family_t family,in_port_t port,in_addr_t addr);
void insert_head(char*name,node*H,sa_family_t family,in_port_t port,in_addr_t addr);
void dele_data(node*H,struct sockaddr_in *caddr,size_t len);
char *search_data(node*H,struct sockaddr_in *caddr,size_t len);
MSG_t text;
int main(int argc, char const *argv[])
{
    //1.创建数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }
    //ipv4
    struct sockaddr_in serveraddr, caddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[1]));
    serveraddr.sin_addr.s_addr = inet_addr("0.0.0.0");

    socklen_t len = sizeof(caddr);

    //绑定
    if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
    {
        perror("bind err.");
        return -1;
    }
    node*H=head_creat();
    //循环收消息
    char buf[128]="";
    char user_name[23];
    int recvbyte;
    while (1)
    {
        recvbyte = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len);
        if (recvbyte < 0)
        {
            perror("recvfrom err.");
            return -1;
        }
        printf("ip:%s port:%d buf:%s\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port), buf);
        if(!strncmp(buf,"User name",9))
        {
            memset(user_name,0,23);
            strncpy(user_name,buf+9,23);
            insert_head(user_name,H,caddr.sin_family,caddr.sin_port,caddr.sin_addr.s_addr);
            memset(buf,0,128);
            strncpy(buf,"Login successful",17);
            sendto(sockfd, buf,sizeof(buf), 0, (struct sockaddr *)&caddr, sizeof(caddr));
            if(H->len>1)
            {
                node*p=H->next->next;
                memset(buf,0,128);
                strcpy(buf,user_name);
                strcat(buf," is logged in");
                for(int i=0;i<H->len-1;i++)
                {
                    sendto(sockfd,buf,sizeof(buf), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
                    p=p->next;
                }
            }
        }
        else if(!strncmp(buf,"quit",5))
        {
            memset(buf,0,128);
            char quit_name[23];
            char*q_name=search_data(H,&caddr,len);
            strcpy(quit_name,q_name);
            dele_data(H,&caddr,len);
            if(H->len>0)
            {
                node*p=H->next;
                memset(buf,0,128);
                strcpy(buf,user_name);
                strcat(buf," logs out");
                for(int i=0;i<H->len;i++)
                {
                    sendto(sockfd,buf,sizeof(buf), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
                    p=p->next;
                }
            }
        }
        else
        {
            
            char test_name[23];
            char*t_name=search_data(H,&caddr,len);
            strcpy(test_name,t_name);
            strcpy(text.name,test_name);
            strncat(text.name," Send a message:",17);
            strcpy(text.text,buf);
            node*p=H->next;
            for(int i=0;i<H->len;i++)
            {
                sendto(sockfd,text.name,sizeof(text.name), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
                sendto(sockfd,text.text,sizeof(text.text), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));
                p=p->next;
            }
        }
    }
    close(sockfd);
    return 0;
}
node*head_creat()
{
    node*H=(node*)malloc(sizeof(node));
    if(NULL==H)
    {
        printf("内存申请失败\n");
        return NULL;
    }
    else
    {
        H->len=0;
        H->next=NULL;
        printf("内存申请成功\n");
        return H;
    }
}

node*creat_node(char*name,sa_family_t family,in_port_t port,in_addr_t addr)
{
    node*p=(node*)malloc(sizeof(node));
    if(NULL==p)
    {
        printf("内存申请失败\n");
        return NULL;
    }
    else
    {
        strcpy(p->user_name,name);
        p->addr.sin_family=family;
        p->addr.sin_port=port;
        p->addr.sin_addr.s_addr=addr;
        p->next=NULL;
        return p;
    }
}

void insert_head(char*name,node*H,sa_family_t family,in_port_t port,in_addr_t addr)
{
    if(H==NULL)
    {
        printf("入参为空,请检查\n");
        return;
    }
    node*p=creat_node(name,family,port,addr);
    p->next=H->next;
    H->next=p;
    H->len++;
}

void dele_data(node*H,struct sockaddr_in *caddr,size_t len)
{
    if(H==NULL)
    {
        printf("入参为空\n");
        return;
    }
    struct sockaddr_in *d_addr;
    node*p=H;
    for(int i=0;i<H->len;i++)
    {
        d_addr=&p->next->addr;
        if(!memcmp(caddr,d_addr,len))
        {
            node*q=p->next;
            p->next=p->next->next;
            free(q);
            H->len--;
            return;
        }
        else
        {
            p=p->next;
        }
    }
    printf("err not dele\n");
}

char *search_data(node*H,struct sockaddr_in *caddr,size_t len)
{
    if(H==NULL)
    {
        printf("入参为空\n");
        return NULL;
    }
    struct sockaddr_in *s_addr;
    node*p=H;
    for(int i=0;i<H->len;i++)
    {
        s_addr=&p->next->addr;
        if(!memcmp(caddr,s_addr,len))
        {
            return p->next->user_name;
        }
        else
        {
            p=p->next;
        }
    }  
    printf("err not serch\n"); 
}

二、客户端模块

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

int main(int argc, char const *argv[])
{
    //1.创建数据报套接子
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }
    //ipv4
    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]);

    socklen_t len = sizeof(serveraddr);

    char buf[128] = "User name";
    char name[119];
    int recvbyte;
    //输入用户名
    printf("please input User name\n");
    fgets(name, sizeof(name), stdin);
    if (name[strlen(name) - 1] == '\n')
        name[strlen(name) - 1] = '\0';
    strcat(buf, name);
    sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr));

    pid_t pid = fork();
    if (pid < 0)
    {
        perror("fork err\n");
        return -1;
    }
    else if (pid == 0)
    {
        while (1)
        {
            recvbyte = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&serveraddr, &len);
            if (recvbyte < 0)
            {
                perror("recv server err\n");
                return -1;
            }
            printf("%s\n", buf);
        }
    }
    else
    {
        while (1)
        {
            fgets(buf, sizeof(buf), stdin);
            if (buf[strlen(buf) - 1] == '\n')
                buf[strlen(buf) - 1] = '\0';
            sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
            if(!strncmp(buf,"quit",5))
            {
                kill(pid,SIGINT);
                wait(NULL);
                break;
            }
        }
    }
    close(sockfd);
    return 0;
}

三、测试图

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜂蜂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值