当前位置:   article > 正文

UDP客户端和服务器_udp客户端和服务端

udp客户端和服务端

UDP客户端,也就是首先主动发送数据的一方,也就是发起服务请求的一方。

UDP服务器,也就是首先等待接收数据,并对接收的数据进行处理,返回计算结果的一方,也就是提供服务的一方。

在下面实验中使用到的函数

int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
  1. ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
  2. struct sockaddr *src_addr, socklen_t *addrlen);
  1. ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
  2. const struct sockaddr *dest_addr, socklen_t addrlen);
  1. int connect(int sockfd, const struct sockaddr *addr,
  2. socklen_t addrlen);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
int send(int s, const void *msg, size_t len, int flags);
in_addr_t inet_addr(const char *cp);
uint16_t htons(uint16_t hostshort);

 udp客户端测试

测试代码 

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <sys/epoll.h>
  7. #include <errno.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <pthread.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <time.h>
  15. #define _DEBUG_INFO
  16. #ifdef _DEBUG_INFO
  17. #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
  18. ,__FILE__,__func__,__LINE__ \
  19. , ##__VA_ARGS__)
  20. #else
  21. #define DEBUG_INFO(format, ...)
  22. #endif
  23. int main(int argc, char *argv[])
  24. {
  25. int client_socket;
  26. client_socket = socket(AF_INET,SOCK_DGRAM,0);
  27. DEBUG_INFO("client_socket = %d",client_socket);
  28. struct sockaddr_in server_addr;
  29. server_addr.sin_port = htons(6600);
  30. server_addr.sin_family = AF_INET;
  31. server_addr.sin_addr.s_addr = inet_addr("192.168.0.5");
  32. char buf[100];
  33. snprintf(buf,sizeof(buf),"time=%d",time(NULL));
  34. DEBUG_INFO("server_addr %s:%d on socket %d\n",
  35. inet_ntoa(server_addr.sin_addr),
  36. htons(server_addr.sin_port),
  37. client_socket);
  38. socklen_t addrlen = sizeof(server_addr);
  39. int send_len = sendto(client_socket,buf,strlen(buf),0,&server_addr,sizeof(server_addr));
  40. memset(buf,0,sizeof(buf));
  41. DEBUG_INFO("sendto %s:%d \n",
  42. inet_ntoa(server_addr.sin_addr),
  43. htons(server_addr.sin_port));
  44. int read_len = recvfrom(client_socket,buf,sizeof(buf),0,&server_addr,&addrlen);
  45. DEBUG_INFO("recvfrom %s:%d -- %s\n",
  46. inet_ntoa(server_addr.sin_addr),
  47. htons(server_addr.sin_port),
  48. buf);
  49. sleep(5);
  50. return 0;
  51. }

UDP接收端(服务器)

执行代码:

  

实验解析 

 UDP客户端向192.168.0.5:6600 地址发送时间值,UDP接受端,也就是调试助手,返回一个字符串。然后UDP客户端等待5秒退出。这可以用来实现一个NTP服务器

UDP服务端 

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <sys/epoll.h>
  7. #include <errno.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <pthread.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. // #define _DEBUG_INFO
  15. #ifdef _DEBUG_INFO
  16. #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
  17. ,__FILE__,__func__,__LINE__ \
  18. , ##__VA_ARGS__)
  19. #else
  20. #define DEBUG_INFO(format, ...)
  21. #endif
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. #include <sys/socket.h>
  25. #include <netinet/in.h>
  26. #include <arpa/inet.h>
  27. #include <sys/epoll.h>
  28. #include <errno.h>
  29. #include <unistd.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <pthread.h>
  33. #include <signal.h>
  34. #include <fcntl.h>
  35. #include <time.h>
  36. #define _DEBUG_INFO
  37. #ifdef _DEBUG_INFO
  38. #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
  39. ,__FILE__,__func__,__LINE__ \
  40. , ##__VA_ARGS__)
  41. #else
  42. #define DEBUG_INFO(format, ...)
  43. #endif
  44. int main(int argc, char *argv[])
  45. {
  46. int server_socket;
  47. int res = 0;
  48. int on = 1;
  49. server_socket = socket(AF_INET,SOCK_DGRAM,0);
  50. DEBUG_INFO("server_socket = %d",server_socket);
  51. if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,&on,sizeof(on)) < 0){
  52. perror("setsockopt");
  53. exit(-1);
  54. }
  55. struct sockaddr_in server_addr;
  56. server_addr.sin_port = htons(6600);
  57. server_addr.sin_family = AF_INET;
  58. server_addr.sin_addr.s_addr = inet_addr("192.168.0.11");
  59. res = bind(server_socket,(const struct sockaddr *)&server_addr,sizeof(server_addr));
  60. if(res == -1){
  61. perror("bind");
  62. return -1;
  63. }
  64. int len = 0;
  65. char buf[100];
  66. socklen_t addrlen;
  67. struct sockaddr_in client_server;
  68. while(1){
  69. memset(buf,0,sizeof(buf));
  70. memcpy(&client_server,&server_addr,sizeof(client_server));
  71. addrlen = sizeof(client_server);
  72. recvfrom(server_socket,buf,sizeof(buf),0,&client_server,&addrlen);
  73. DEBUG_INFO("buf = %s",buf);
  74. DEBUG_INFO("recfrom %s:%d -- %s\n",
  75. inet_ntoa(client_server.sin_addr),
  76. htons(client_server.sin_port),
  77. buf);
  78. addrlen = sizeof(client_server);
  79. sendto(server_socket,buf,strlen(buf),0,&client_server,addrlen);
  80. }
  81. sleep(5);
  82. return 0;
  83. }

修改客户端中的IP地址为192.168.0.11,也就是虚拟机的IP地址

 实验解析:

服务器等待接收数据。客户端向服务端发送数据,服务器端接收数据后,将数据原样返回。然后服务端继续等待接收数据。客户端发送完毕后等待接收,接收到数据后睡眠5秒退出程序。

使用connect的客户端 

虽然UDP是无连接的,但是connect函数依然有效,它高速操作系统,默认从哪里接收数据,默认向谁发送数据。这样就可以使用read,wirte、send、recv这四个没有指定地址的函数来收发数据了。

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <sys/epoll.h>
  7. #include <errno.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <pthread.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <time.h>
  15. #define _DEBUG_INFO
  16. #ifdef _DEBUG_INFO
  17. #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
  18. ,__FILE__,__func__,__LINE__ \
  19. , ##__VA_ARGS__)
  20. #else
  21. #define DEBUG_INFO(format, ...)
  22. #endif
  23. int main(int argc, char *argv[])
  24. {
  25. int client_socket;
  26. int res = 0;
  27. client_socket = socket(AF_INET,SOCK_DGRAM,0);
  28. DEBUG_INFO("client_socket = %d",client_socket);
  29. struct sockaddr_in remote_addr;
  30. remote_addr.sin_port = htons(6600);
  31. remote_addr.sin_family = AF_INET;
  32. remote_addr.sin_addr.s_addr = inet_addr("192.168.0.11");
  33. char buf[100];
  34. snprintf(buf,sizeof(buf),"time=%d",time(NULL));
  35. DEBUG_INFO("remote_addr %s:%d on socket %d\n",
  36. inet_ntoa(remote_addr.sin_addr),
  37. htons(remote_addr.sin_port),
  38. client_socket);
  39. res = connect(client_socket,&remote_addr,sizeof(remote_addr));
  40. int send_len = send(client_socket,buf,strlen(buf),0);
  41. memset(buf,0,sizeof(buf));
  42. int read_len = recv(client_socket,buf,sizeof(buf),0);
  43. DEBUG_INFO("recv %s:%d -- %s\n",
  44. inet_ntoa(remote_addr.sin_addr),
  45. htons(remote_addr.sin_port),
  46. buf);
  47. sleep(5);
  48. return 0;
  49. }

 测试结果:

既是客户端和也是服务端

如果一个客户端,偶尔也要提供服务的话,那么它绑定(bind)一个明确的本地端口是有必要的,这样别人就知道应该如何主动向它发起通讯了。下面是使用bind绑定本地端口的客户端代码

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <sys/epoll.h>
  7. #include <errno.h>
  8. #include <unistd.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <pthread.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <time.h>
  15. #define _DEBUG_INFO
  16. #ifdef _DEBUG_INFO
  17. #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
  18. ,__FILE__,__func__,__LINE__ \
  19. , ##__VA_ARGS__)
  20. #else
  21. #define DEBUG_INFO(format, ...)
  22. #endif
  23. int main(int argc, char *argv[])
  24. {
  25. int client_socket;
  26. int res = 0;
  27. client_socket = socket(AF_INET,SOCK_DGRAM,0);
  28. DEBUG_INFO("client_socket = %d",client_socket);
  29. struct sockaddr_in remote_addr;
  30. remote_addr.sin_port = htons(6600);
  31. remote_addr.sin_family = AF_INET;
  32. remote_addr.sin_addr.s_addr = inet_addr("192.168.0.11");
  33. DEBUG_INFO("INADDR_ANY = %d",INADDR_ANY);
  34. struct sockaddr_in local_addr;
  35. local_addr.sin_port = htons(6700);
  36. local_addr.sin_family = AF_INET;
  37. local_addr.sin_addr.s_addr = INADDR_ANY;//inet_addr("192.168.0.11");
  38. res = bind(client_socket,(const struct sockaddr *)&local_addr,sizeof(local_addr));
  39. if(res == -1){
  40. perror("bind");
  41. return -1;
  42. }
  43. char buf[100];
  44. snprintf(buf,sizeof(buf),"time=%d",time(NULL));
  45. DEBUG_INFO("remote_addr %s:%d on socket %d\n",
  46. inet_ntoa(remote_addr.sin_addr),
  47. htons(remote_addr.sin_port),
  48. client_socket);
  49. res = connect(client_socket,&remote_addr,sizeof(remote_addr));
  50. int send_len = send(client_socket,buf,strlen(buf),0);
  51. memset(buf,0,sizeof(buf));
  52. int read_len = recv(client_socket,buf,sizeof(buf),0);
  53. DEBUG_INFO("recv %s:%d -- %s\n",
  54. inet_ntoa(remote_addr.sin_addr),
  55. htons(remote_addr.sin_port),
  56. buf);
  57. sleep(5);
  58. return 0;
  59. }

执行结果: 

 实验解析:

服务端使用前面的测试代码。这样通讯两端的IP和PORT就都是已知的了,这样比较适合新手,特别是两边都是经验不足的开发人员。防止思维混乱。

 

小结

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/179960
推荐阅读
相关标签
  

闽ICP备14008679号