• UDP聊天室


    1.头文件

    1. /*===============================================
    2. * 文件名称:UDP.h
    3. * 创 建 者:crx
    4. * 创建日期:2023年09月3日
    5. * 描 述:
    6. ================================================*/
    7. #ifndef _UDP_H
    8. #define _UDP_H
    9. #include
    10. #include /* See NOTES */
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. typedef struct node{ //链表节点保存用户地址结构体信息
    21. struct sockaddr_in caddr;
    22. struct node *next;
    23. }Node,*Pnode;
    24. typedef struct mesg{ //用户状态、姓名、消息
    25. char state;
    26. char name[20];
    27. char text[60];
    28. }Mesg;
    29. enum state{ //状态:登录、转发、下线
    30. Login,
    31. Relay,
    32. Quit,
    33. };
    34. //创建头节点
    35. Pnode create_node();
    36. //插入,登录
    37. int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg);
    38. //转发
    39. void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg);
    40. //删除,下线
    41. int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg);
    42. #endif

    2.服务器

    1. /*===============================================
    2. * 文件名称:UDPs.c
    3. * 创 建 者:crx
    4. * 创建日期:2023年09月3日
    5. * 描 述:
    6. ================================================*/
    7. #include "UDP.h"
    8. int main(int argc, char *argv[])
    9. {
    10. //1.创建套接字
    11. int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    12. if(-1 == sockfd)
    13. {
    14. perror("socket");
    15. return -1;
    16. }
    17. //2.绑定
    18. struct sockaddr_in saddr;
    19. saddr.sin_family = AF_INET;
    20. saddr.sin_port = htons(8181);
    21. saddr.sin_addr.s_addr = INADDR_ANY;
    22. int bindfd = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
    23. if(-1 == bindfd)
    24. {
    25. perror("bind");
    26. return -1;
    27. }
    28. //3.准备保存客户端地址结构体,等待登录
    29. printf("等待登录....\n");
    30. struct sockaddr_in caddr;
    31. socklen_t addrlen = sizeof(caddr);
    32. Mesg msg;
    33. //4.创建头节点
    34. Pnode p = create_node();
    35. Pnode q = p;
    36. Pnode temp = p;
    37. while(1)
    38. {
    39. memset(&caddr,0,sizeof(caddr));
    40. //5.接收用户登录信息
    41. recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&addrlen);
    42. //6.根据用户状态执行对应操作
    43. //msg.state = Login
    44. //用户登录,链表插入用户信息
    45. //判断链表是否为空,为空则插入用户
    46. //链表不为空,判断是否是链表中已有用户,不是则插入用户信息
    47. //转发登录消息给其他在线用户
    48. if(msg.state == Login)
    49. {
    50. if(NULL == q->next)
    51. {
    52. insert_node(p,caddr,msg);
    53. strcpy(msg.text,"已登录!");
    54. }
    55. else
    56. {
    57. temp = p->next;
    58. while(temp)
    59. {
    60. if(temp->caddr.sin_port == caddr.sin_port && temp->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr)
    61. break;
    62. else
    63. temp = temp->next;
    64. }
    65. if(NULL == temp)
    66. {
    67. insert_node(p,caddr,msg);
    68. strcpy(msg.text,"已登录!");
    69. relay(sockfd,p,caddr,msg);
    70. }
    71. }
    72. }
    73. //msg.state = Relay
    74. //转发用户信息给其他在线用户
    75. if(msg.state == Relay)
    76. {
    77. relay(sockfd,p,caddr,msg);
    78. }
    79. //msg.state = Quit
    80. //用户下线
    81. //链表中删除用户信息
    82. //转发用户下线信息给其他用户
    83. if(msg.state == Quit)
    84. {
    85. delete_node(p,caddr,msg);
    86. strcpy(msg.text,"已下线");
    87. relay(sockfd,p,caddr,msg);
    88. }
    89. }
    90. return 0;
    91. }
    92. //创建头节点
    93. Pnode create_node()
    94. {
    95. Pnode p = (Pnode)malloc(sizeof(Node));
    96. if(NULL == p)
    97. {
    98. perror("malloc");
    99. return NULL;
    100. }
    101. p->next = NULL;
    102. return p;
    103. }
    104. //插入,登录
    105. int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg)
    106. {
    107. if(NULL == p)
    108. {
    109. return -1;
    110. }
    111. Pnode new = (Pnode)malloc(sizeof(Node));
    112. if(NULL == new)
    113. {
    114. perror("malloc");
    115. return -2;
    116. }
    117. new->next = p->next;
    118. p->next = new;
    119. new->caddr = caddr;
    120. printf("已登录!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
    121. return 1;
    122. }
    123. //转发
    124. void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg) {
    125. while(p->next)
    126. {
    127. p = p->next;
    128. if(p->caddr.sin_port == caddr.sin_port && p->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr)
    129. {
    130. continue;
    131. }
    132. else
    133. {
    134. sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
    135. }
    136. }
    137. }
    138. //删除,下线
    139. int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg)
    140. {
    141. if(NULL == p)
    142. {
    143. return -1;
    144. }
    145. while(p->next)
    146. {
    147. if(memcmp(&(p->next->caddr),&caddr,sizeof(caddr)) == 0)
    148. {
    149. Pnode q = p->next;
    150. p->next = q->next;
    151. free(q);
    152. break;
    153. }
    154. else
    155. {
    156. p = p->next;
    157. }
    158. }
    159. printf("已下线!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
    160. }

    3.客户端

    1. /*===============================================
    2. * 文件名称:UDPc.c
    3. * 创 建 者:crx
    4. * 创建日期:2023年09月3日
    5. * 描 述:
    6. ================================================*/
    7. #include "UDP.h"
    8. int main(int argc, char *argv[])
    9. {
    10. //1.创建套接字
    11. int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    12. if(-1 == sockfd)
    13. {
    14. perror("socket");
    15. return -1;
    16. }
    17. //2.服务器地址
    18. struct sockaddr_in saddr;
    19. saddr.sin_family = AF_INET;
    20. saddr.sin_port = htons(8181);
    21. saddr.sin_addr.s_addr = inet_addr("192.168.17.225");
    22. //3.创建用户
    23. Mesg msg;
    24. //4.运行后触发msg.state = Login
    25. //登录填写用户名
    26. //发送给服务器登录信息转发登录消息操作
    27. printf("登录\n");
    28. msg.state = Login;
    29. printf("请输入用户名:\n");
    30. fgets(msg.name,20,stdin);
    31. printf("******************************************\n");
    32. if(msg.name[strlen(msg.name)-1] == '\n')
    33. msg.name[strlen(msg.name) -1] = '\0';
    34. //发送用户登录消息
    35. if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr)))
    36. {
    37. perror("sendto");
    38. return -1;
    39. }
    40. //5.创建子进程
    41. pid_t pid = fork();
    42. //6.子进程循环接收其他用户消息并打印发送人及信息
    43. if(pid == 0)
    44. {
    45. while(1)
    46. {
    47. socklen_t addrlen = sizeof(saddr);
    48. recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,&addrlen);
    49. printf("~%s~ : %s\n",msg.name,msg.text);
    50. }
    51. }
    52. else
    53. {
    54. //7.父进程获取用户终端输入到用户消息中
    55. while(1)
    56. {
    57. fgets(msg.text,sizeof(msg.text),stdin);
    58. if(msg.text[strlen(msg.text)-1] == '\n')
    59. msg.text[strlen(msg.text) -1] = '\0';
    60. //8.处理终端输入
    61. //终端输入Quit则触发msg.state = Quit
    62. //发送给服务器下线信息执行对应操作
    63. //使用SIGKILL强制结束进程
    64. if(strcmp(msg.text,"Quit") == 0)
    65. {
    66. msg.state = Quit;
    67. if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr)))
    68. {
    69. perror("sendto");
    70. return -1;
    71. }
    72. kill(pid,SIGKILL);
    73. wait(NULL);
    74. exit(0);
    75. }
    76. //终端输入不是Quit则触发msg.state = Relay
    77. //发送给服务端执行转发操作
    78. else
    79. {
    80. msg.state = Relay;
    81. }
    82. if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr)))
    83. {
    84. perror("sendto");
    85. return -1;
    86. }
    87. }
    88. }
    89. close(sockfd);
    90. return 0;
    91. }

    4.makefile

    1. all:UDPs UDPc
    2. UDPs:UDPs.c
    3. gcc UDPs.c -o UDPs
    4. UDPc:UDPc.c
    5. gcc UDPc.c -o UDPc
    6. clean:
    7. rm UDPs UDPc

    5.结果

  • 相关阅读:
    【Python搜索算法】广度优先搜索(BFS)算法原理详解与应用,示例+代码
    图学习【参考资料2】-知识补充与node2vec代码注解
    网络防火墙技术知多少?了解如何保护您的网络安全
    006:连续跌三天,第四天上涨的概率--用python统计
    信息发布门槛低,移动互联网时代下的网络舆情如何防控?
    【FNN分类】基于粒子群结合引力搜索算法优化前向反馈神经网络实现数据分类附matlab代码
    Java序列化与反序列化
    微服务项目:尚融宝(52)(核心业务流程:充值服务(2))
    GPT-4成Nature审稿人,超 50% 结果和人类评审一致
    Mybatis详细的使用过程(3)
  • 原文地址:https://blog.csdn.net/cxy255256/article/details/132650132