• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

使用UDP协议构建简易局域网内聊天室

武飞扬头像
LEELOUo
帮助1

实现功能:

 客户端

1.开启时输入昵称并往服务器端发送带有客户端昵称

2.开启后能随时往服务器端发送聊天内容

3.收到服务器发来的数据时判别是否为自己发送的数据,若不是则输出num编号所指引的内容

4. 当输入quit时退出

 服务器

1.接受各个客户端的信息,新用户则将其存入链表中并向各个用户发送有新用户加入的信息

2.当用户输入quit时,删除该用户信息并向各个用户发送该用户退出的信息

3.当收到正常聊天信息时发送给各个用户

代码

客户端

客户端中ip设定为本机的ip地址,通过外部传参传入不同的端口号用以区分不同用户

  1.  
    #include <sys/types.h>
  2.  
    #include <stdio.h>
  3.  
    #include <sys/socket.h>
  4.  
    #include <netinet/in.h>
  5.  
    #include <arpa/inet.h>
  6.  
    #include <string.h>
  7.  
    #include <unistd.h>
  8.  
    #include <pthread.h>
  9.  
    #include <stdlib.h>
  10.  
    #define ERR_MSG(msg) do {\
  11.  
    fprintf(stderr,"_%d_",__LINE__);\
  12.  
    perror(msg);\
  13.  
    }while(0)
  14.  
    #define IP "192.168.31.242"
  15.  
    //#define PORT 8888 // 1024~49151
  16.  
    typedef struct MSG{
  17.  
    int num;
  18.  
    char name[20];
  19.  
    char data[256];
  20.  
    }MSG;
  21.  
     
  22.  
    int sfd;
  23.  
    struct sockaddr_in cin;
  24.  
    socklen_t addrlen= sizeof(cin);
  25.  
    MSG msg;
  26.  
    char cname[20];
  27.  
    void *shou(void*arg)
  28.  
    {
  29.  
     
  30.  
    while(1)
  31.  
    {
  32.  
     
  33.  
    if(recv(sfd, &msg, sizeof(msg),0) < 0)
  34.  
    {
  35.  
    ERR_MSG("recvfrom");
  36.  
    return NULL;
  37.  
    }
  38.  
     
  39.  
    if (strcmp(msg.name,cname)!=0) //判断是否为自己发送的
  40.  
    {
  41.  
    if(msg.num==3)
  42.  
    {
  43.  
    printf("%s:%s\n",msg.name,msg.data);
  44.  
    }
  45.  
    if (msg.num==4)
  46.  
    {
  47.  
    printf("%s进入聊天室\n",msg.name);
  48.  
    }
  49.  
    }
  50.  
     
  51.  
    }
  52.  
    pthread_exit(NULL);
  53.  
     
  54.  
    }
  55.  
     
  56.  
     
  57.  
     
  58.  
    void *fa(void*arg)
  59.  
    {
  60.  
     
  61.  
     
  62.  
    while(1)
  63.  
    {
  64.  
     
  65.  
    scanf("%s",msg.data);
  66.  
     
  67.  
    msg.num=2;
  68.  
    strcpy(msg.name,cname);
  69.  
     
  70.  
    if(sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cin, sizeof(cin)) < 0)
  71.  
    {
  72.  
    ERR_MSG("recvfrom");
  73.  
    return NULL;
  74.  
    }
  75.  
    if (strcmp(msg.data,"quit")==0)
  76.  
    {
  77.  
    exit(0);
  78.  
    }
  79.  
     
  80.  
     
  81.  
    }
  82.  
    pthread_exit(NULL);
  83.  
     
  84.  
     
  85.  
    }
  86.  
     
  87.  
     
  88.  
     
  89.  
     
  90.  
     
  91.  
    //绑定一个广播ip的端口试试
  92.  
     
  93.  
    int main(int argc, const char *argv[])
  94.  
    {
  95.  
     
  96.  
    //创建报式套接字
  97.  
    sfd =socket(AF_INET,SOCK_DGRAM,0);
  98.  
    if (sfd<0)
  99.  
    {
  100.  
    ERR_MSG("socket");
  101.  
    return -1;
  102.  
    }
  103.  
    printf("create socket success\n");
  104.  
     
  105.  
     
  106.  
    int broad =1;
  107.  
    if (setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&broad,sizeof(broad))<0)
  108.  
    {
  109.  
    ERR_MSG("setsockopt");
  110.  
    return -1;
  111.  
    }
  112.  
     
  113.  
     
  114.  
    //填充地址信息结构体,真实的地址信息结构体与协议族有关
  115.  
    //AF_INEt 详见 man 7 ip
  116.  
    struct sockaddr_in sin;
  117.  
    sin.sin_family =AF_INET;
  118.  
    sin.sin_port =htons(8888);//主机字节序转网络字节序的端口号
  119.  
    sin.sin_addr.s_addr = inet_addr("192.168.31.255");
  120.  
    cin = sin;
  121.  
     
  122.  
    int port = atoi(argv[1]);
  123.  
    struct sockaddr_in bin;
  124.  
    bin.sin_family =AF_INET;
  125.  
    bin.sin_port =htons(port);//主机字节序转网络字节序的端口号
  126.  
    bin.sin_addr.s_addr = inet_addr(IP);
  127.  
     
  128.  
    if(bind(sfd,(struct sockaddr*)&bin,sizeof(bin))==-1)
  129.  
    {
  130.  
    ERR_MSG("bind");
  131.  
    return -1;
  132.  
    }
  133.  
     
  134.  
    ssize_t res=0;
  135.  
     
  136.  
    printf("请输入用户名:");
  137.  
    scanf("%s",msg.name);
  138.  
    msg.num=1;//num为1时内容为名字
  139.  
    strcpy(cname,msg.name);
  140.  
    sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin, addrlen);
  141.  
     
  142.  
    msg.num=2; //num为2时内容为聊天内容
  143.  
     
  144.  
    //将客户端的收发分别写入两个线程,这样就可以同时运行
  145.  
    pthread_t tid1,tid2;
  146.  
    if (pthread_create(&tid1,NULL,shou,NULL)!=0)
  147.  
    {
  148.  
    ERR_MSG("pthread_create");
  149.  
    return -1;
  150.  
    }
  151.  
     
  152.  
    if (pthread_create(&tid2,NULL,fa,NULL)!=0)
  153.  
    {
  154.  
    ERR_MSG("pthread_create");
  155.  
    return -1;
  156.  
    }
  157.  
     
  158.  
     
  159.  
     
  160.  
     
  161.  
    pthread_join(tid1,NULL);
  162.  
    pthread_join(tid2,NULL);
  163.  
    close(sfd);
  164.  
     
  165.  
     
  166.  
     
  167.  
    return 0;
  168.  
    }
学新通

服务器端 

  1.  
    #include <sys/types.h>
  2.  
    #include <stdio.h>
  3.  
    #include <sys/socket.h>
  4.  
    #include <netinet/in.h>
  5.  
    #include <arpa/inet.h>
  6.  
    #include <string.h>
  7.  
    #include <unistd.h>
  8.  
    #include <stdlib.h>
  9.  
    #include <pthread.h>
  10.  
    #define ERR_MSG(msg) do {\
  11.  
    fprintf(stderr,"_%d_",__LINE__);\
  12.  
    perror(msg);\
  13.  
    }while(0)
  14.  
     
  15.  
    typedef struct MSG{
  16.  
    int num;
  17.  
    char name[20];
  18.  
    char data[256];
  19.  
     
  20.  
    }MSG;
  21.  
     
  22.  
    MSG msg;
  23.  
    int sfd;
  24.  
    struct sockaddr_in cin;
  25.  
    socklen_t addrlen= sizeof(cin);
  26.  
     
  27.  
    typedef struct Node{
  28.  
    union{
  29.  
    int len;
  30.  
    struct sockaddr_in nin;
  31.  
    };
  32.  
    struct Node * next;
  33.  
    }List; //定义一个链表用于存放用户信息
  34.  
     
  35.  
     
  36.  
     
  37.  
     
  38.  
     
  39.  
     
  40.  
     
  41.  
    int main(int argc, const char *argv[])
  42.  
    {
  43.  
     
  44.  
    //创建报式套接字
  45.  
    sfd =socket(AF_INET,SOCK_DGRAM,0);
  46.  
    if (sfd<0)
  47.  
    {
  48.  
    ERR_MSG("socket");
  49.  
    return -1;
  50.  
    }
  51.  
    printf("create socket success\n");
  52.  
     
  53.  
    int broad =1;
  54.  
    if (setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&broad,sizeof(broad))<0)
  55.  
    {
  56.  
    ERR_MSG("setsockopt");
  57.  
    return -1;
  58.  
    }
  59.  
    MSG msg;
  60.  
     
  61.  
    //填充地址信息结构体,真实的地址信息结构体与协议族有关
  62.  
    //AF_INEt 详见 man 7 ip
  63.  
    struct sockaddr_in sin;
  64.  
    sin.sin_family =AF_INET;
  65.  
    sin.sin_port =htons(8888);//主机字节序转网络字节序的端口号
  66.  
    sin.sin_addr.s_addr = inet_addr("192.168.31.255");
  67.  
    if (bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
  68.  
    {
  69.  
    ERR_MSG("bind");
  70.  
    return -1;
  71.  
    }
  72.  
     
  73.  
     
  74.  
    List *l= (List*)malloc(sizeof(List));
  75.  
    if (NULL==l)
  76.  
    {
  77.  
    ERR_MSG("malloc");
  78.  
    return -1;
  79.  
    }
  80.  
    l->len=0;
  81.  
    l->next=NULL;
  82.  
    List * p =NULL;
  83.  
    List * q=NULL;
  84.  
     
  85.  
    ssize_t res=0;
  86.  
     
  87.  
    while (1)
  88.  
    {
  89.  
    res = recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&addrlen);
  90.  
    if(res == -1)
  91.  
    {
  92.  
    ERR_MSG("recvfrom");
  93.  
    return -1;
  94.  
    }else if (res>0)//读取成功
  95.  
    {
  96.  
    if (msg.num==1)//新用户,需a要写入链表
  97.  
    {
  98.  
    printf("[%s:%d]\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
  99.  
    //使用头插将新用户插入链表中
  100.  
    p= (List*)malloc(sizeof(List));
  101.  
    if (NULL==p)
  102.  
    {
  103.  
    ERR_MSG("malloc");
  104.  
    return -1;
  105.  
    }
  106.  
     
  107.  
    p->next=l->next;
  108.  
    p->nin=cin;
  109.  
    l->next=p;
  110.  
    l->len ;
  111.  
     
  112.  
    q=l->next;
  113.  
    //广播有新的用户进入聊天
  114.  
    msg.num=4;//防止自己收到后继续输出
  115.  
    while(q!=NULL)
  116.  
    {
  117.  
    if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&q->nin,sizeof(q->nin))<0)
  118.  
    {
  119.  
    ERR_MSG("sendto");
  120.  
    return -1;
  121.  
    }
  122.  
    q=q->next;
  123.  
     
  124.  
    }
  125.  
    }else if(msg.num==2)//老用户
  126.  
    {
  127.  
    printf("[%s:%d]\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
  128.  
    if (strcmp(msg.data,"quit")==0)//用户退出,需要广播退出信息并将其在链表中删除
  129.  
    {
  130.  
    msg.num=3;
  131.  
    strcpy(msg.data,"已退出");
  132.  
    q=l->next;
  133.  
    while(q!=NULL)
  134.  
    {
  135.  
    if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&q->nin,sizeof(q->nin))<0)
  136.  
    {
  137.  
    ERR_MSG("sendto");
  138.  
    return -1;
  139.  
    }
  140.  
    q=q->next;
  141.  
     
  142.  
    }
  143.  
    p=l;
  144.  
    while (p->next!=NULL)
  145.  
    {
  146.  
    if (p->next->nin.sin_port == cin.sin_port)
  147.  
    {
  148.  
    q=p->next->next;
  149.  
    free(p->next);
  150.  
    p->next=q;
  151.  
    break;
  152.  
    }
  153.  
    p=p->next;
  154.  
    }//将该用户在链表中删除
  155.  
     
  156.  
     
  157.  
    }else
  158.  
    {//正常聊天广播收到的内容
  159.  
    msg.num =3;//防止自己收到后继续输出
  160.  
    q=l->next;
  161.  
    while(q!=NULL)
  162.  
    {
  163.  
    if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&q->nin,sizeof(q->nin))<0)
  164.  
    {
  165.  
    ERR_MSG("sendto");
  166.  
    return -1;
  167.  
    }
  168.  
    q=q->next;
  169.  
    }
  170.  
    }
  171.  
    }
  172.  
    }
  173.  
    }
  174.  
    close(sfd);
  175.  
    return 0;
  176.  
    }
学新通

运行测试 :

成功完成预计功能。 

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfcfic
系列文章
更多 icon
同类精品
更多 icon
继续加载