[关闭]
@Dubyoo 2014-06-13T19:28:49.000000Z 字数 4048 阅读 2118

2014-04-03 Linux网络编程 - 基于UDP的多人群聊

  1. /* server.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <arpa/inet.h>
  8. #include <netinet/in.h>
  9. #include <sys/socket.h>
  10. struct LinkNode //链表,储存连接服务器的所有客户端地址信息
  11. {
  12. struct sockaddr_in client_addr ;
  13. struct LinkNode * next ;
  14. }LinkNode;
  15. typedef struct LinkNode* LinkList;
  16. void init_list(LinkList * L) //初始化链表
  17. {
  18. (*L)=(LinkList)malloc(sizeof(LinkNode));
  19. memset(&((*L)->client_addr), 0, sizeof(struct sockaddr_in)) ;
  20. (*L)->next = NULL;
  21. }
  22. void add_client(LinkList L, struct sockaddr_in new_client_addr) //添加新地址
  23. {
  24. LinkList p = L ;
  25. LinkList tail ;
  26. tail = (LinkList)malloc(sizeof(LinkNode)) ;
  27. memset(tail, 0, sizeof(LinkNode)) ;
  28. while(p->next != NULL)
  29. {
  30. p = p->next ;
  31. }
  32. tail->client_addr = new_client_addr ; //可以结构体直接赋值
  33. //tail->client_addr.sin_family = new_client_addr.sin_family ;
  34. //tail->client_addr.sin_port =new_client_addr.sin_port ;
  35. //tail->client_addr.sin_addr.s_addr = new_client_addr.sin_addr.s_addr ;
  36. p->next = tail ;
  37. tail->next = NULL ;
  38. }
  39. void del_client(LinkList L, struct sockaddr_in offline_client) //删除下线客户端地址
  40. {
  41. LinkList del, p = L ;
  42. while(p->next != NULL)
  43. {
  44. if(offline_client.sin_addr.s_addr == p->next->client_addr.sin_addr.s_addr && offline_client.sin_port == p->next->client_addr.sin_port)
  45. break ;
  46. p = p->next ;
  47. }
  48. del = p->next ;
  49. p->next = del->next ;
  50. //free(del) ;
  51. }
  52. int main(int argc, char * argv[]) // ---> ./exe [port]
  53. {
  54. int server_fd, iret ;
  55. char recv_buf[128], send_buf[128], message[128];
  56. struct sockaddr_in server_addr, cli_addr ;
  57. LinkList L, p;
  58. init_list(&L) ;
  59. //socket
  60. server_fd = socket(AF_INET, SOCK_DGRAM, 0) ;
  61. if(server_fd == -1)
  62. {
  63. perror("socket");
  64. exit(-1) ;
  65. }
  66. //bind
  67. memset(&server_addr, 0, sizeof(server_addr)) ;
  68. server_addr.sin_family = AF_INET ;
  69. server_addr.sin_port = htons(atoi(argv[1])) ;
  70. server_addr.sin_addr.s_addr = INADDR_ANY ;
  71. iret = bind(server_fd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) ;
  72. if(iret == -1)
  73. {
  74. perror("bind") ;
  75. exit(-1) ;
  76. }
  77. while(1)
  78. {
  79. //recvfrom
  80. memset(&cli_addr, 0, sizeof(cli_addr)) ;
  81. memset(recv_buf, 0, 128) ;
  82. int len = sizeof(cli_addr) ;
  83. recvfrom(server_fd, recv_buf, 128, 0, (struct sockaddr*)&cli_addr, &len) ;
  84. //add_client
  85. if(strcmp(recv_buf, "online\n") == 0) //有客户端上线时新增地址到链表
  86. {
  87. add_client(L, cli_addr) ;
  88. printf("online!!!\n") ;
  89. }
  90. //del_client
  91. else if(strcmp(recv_buf, "offline\n") == 0) //客户端下线时删除该地址
  92. {
  93. del_client(L, cli_addr) ;
  94. printf("offline!!!\n") ;
  95. }
  96. //printf("receive from ip : %s, port : %d, message : %s\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), recv_buf) ; //测试服务器端是否收到消息
  97. memset(message, 0, 128) ;
  98. sprintf(message, "from ip : %s, port : %d\nmessage : %s\n",inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), recv_buf) ; //给message添加发信客户端信息
  99. //sendto
  100. p = L ;
  101. while(p->next != NULL) //向链表内存储的全部客户端地址发消息
  102. {
  103. p = p->next ;
  104. strcpy(send_buf, message) ;
  105. sendto(server_fd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&(p->client_addr), sizeof(cli_addr)) ;
  106. }
  107. }
  108. //close
  109. close(server_fd) ;
  110. return 0;
  111. }
  1. /* client.c */ //可以有多个客户端同时通过服务器收发消息
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <arpa/inet.h>
  8. #include <netinet/in.h>
  9. #include <sys/socket.h>
  10. #include <pthread.h>
  11. void * thd_handle(void * arg) //子线程,负责接收消息
  12. {
  13. int client_fd = *(int*)arg ;
  14. char recv_buf[128] ;
  15. struct sockaddr_in server_addr ;
  16. while(1)
  17. {
  18. //recvfrom
  19. memset(&server_addr, 0, sizeof(server_addr)) ;
  20. memset(recv_buf, 0, 128) ;
  21. int len = sizeof(server_addr) ;
  22. recvfrom(client_fd, recv_buf, 128, 0, (struct sockaddr*)&server_addr, &len) ;
  23. printf("%s", recv_buf) ;
  24. }
  25. }
  26. int main(int argc, char * argv[]) // ---> ./exe ip port
  27. {
  28. int client_fd ;
  29. pthread_t thd ;
  30. char send_buf[128] ;
  31. struct sockaddr_in server_addr;
  32. //socket
  33. client_fd = socket(AF_INET, SOCK_DGRAM, 0) ;
  34. thd = pthread_create(&thd, NULL, thd_handle, (void*)&client_fd) ; //创建收消息线程
  35. if(client_fd == -1)
  36. {
  37. perror("socket") ;
  38. exit(-1) ;
  39. }
  40. memset(&server_addr, 0, sizeof(server_addr)) ;
  41. server_addr.sin_family = AF_INET ;
  42. server_addr.sin_port = htons(atoi(argv[2])) ;
  43. server_addr.sin_addr.s_addr = inet_addr(argv[1]) ;
  44. //sendto (online)
  45. memset(send_buf, 0, 128) ;
  46. strcpy(send_buf, "online\n") ;
  47. sendto(client_fd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)) ; //连接服务器时发送上线信息
  48. while(1)
  49. {
  50. //sendto
  51. memset(send_buf, 0, 128) ;
  52. fgets(send_buf, 128, stdin) ;
  53. sendto(client_fd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)) ;
  54. if(strcmp(send_buf, "offline\n") == 0) //发送offline时下线退出
  55. {
  56. break ;
  57. }
  58. }
  59. //close
  60. close(client_fd) ;
  61. return 0 ;
  62. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注