赞
踩
UDP客户端,也就是首先主动发送数据的一方,也就是发起服务请求的一方。
UDP服务器,也就是首先等待接收数据,并对接收的数据进行处理,返回计算结果的一方,也就是提供服务的一方。
在下面实验中使用到的函数
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
- ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
- struct sockaddr *src_addr, socklen_t *addrlen);
- ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
- const struct sockaddr *dest_addr, socklen_t addrlen);
- int connect(int sockfd, const struct sockaddr *addr,
- 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);
测试代码
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/epoll.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <time.h>
-
- #define _DEBUG_INFO
- #ifdef _DEBUG_INFO
- #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
- ,__FILE__,__func__,__LINE__ \
- , ##__VA_ARGS__)
- #else
- #define DEBUG_INFO(format, ...)
- #endif
-
- int main(int argc, char *argv[])
- {
- int client_socket;
- client_socket = socket(AF_INET,SOCK_DGRAM,0);
- DEBUG_INFO("client_socket = %d",client_socket);
-
- struct sockaddr_in server_addr;
- server_addr.sin_port = htons(6600);
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.s_addr = inet_addr("192.168.0.5");
- char buf[100];
- snprintf(buf,sizeof(buf),"time=%d",time(NULL));
-
- DEBUG_INFO("server_addr %s:%d on socket %d\n",
- inet_ntoa(server_addr.sin_addr),
- htons(server_addr.sin_port),
- client_socket);
- socklen_t addrlen = sizeof(server_addr);
- int send_len = sendto(client_socket,buf,strlen(buf),0,&server_addr,sizeof(server_addr));
- memset(buf,0,sizeof(buf));
- DEBUG_INFO("sendto %s:%d \n",
- inet_ntoa(server_addr.sin_addr),
- htons(server_addr.sin_port));
- int read_len = recvfrom(client_socket,buf,sizeof(buf),0,&server_addr,&addrlen);
- DEBUG_INFO("recvfrom %s:%d -- %s\n",
- inet_ntoa(server_addr.sin_addr),
- htons(server_addr.sin_port),
- buf);
-
- sleep(5);
- return 0;
- }
UDP接收端(服务器)
执行代码:
实验解析
UDP客户端向192.168.0.5:6600 地址发送时间值,UDP接受端,也就是调试助手,返回一个字符串。然后UDP客户端等待5秒退出。这可以用来实现一个NTP服务器
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/epoll.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <signal.h>
- #include <fcntl.h>
-
- // #define _DEBUG_INFO
- #ifdef _DEBUG_INFO
- #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
- ,__FILE__,__func__,__LINE__ \
- , ##__VA_ARGS__)
- #else
- #define DEBUG_INFO(format, ...)
- #endif
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/epoll.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <time.h>
-
- #define _DEBUG_INFO
- #ifdef _DEBUG_INFO
- #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
- ,__FILE__,__func__,__LINE__ \
- , ##__VA_ARGS__)
- #else
- #define DEBUG_INFO(format, ...)
- #endif
-
- int main(int argc, char *argv[])
- {
- int server_socket;
- int res = 0;
- int on = 1;
- server_socket = socket(AF_INET,SOCK_DGRAM,0);
- DEBUG_INFO("server_socket = %d",server_socket);
-
- if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,&on,sizeof(on)) < 0){
- perror("setsockopt");
- exit(-1);
- }
-
- struct sockaddr_in server_addr;
- server_addr.sin_port = htons(6600);
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.s_addr = inet_addr("192.168.0.11");
-
- res = bind(server_socket,(const struct sockaddr *)&server_addr,sizeof(server_addr));
- if(res == -1){
- perror("bind");
- return -1;
- }
- int len = 0;
- char buf[100];
- socklen_t addrlen;
- struct sockaddr_in client_server;
- while(1){
- memset(buf,0,sizeof(buf));
- memcpy(&client_server,&server_addr,sizeof(client_server));
- addrlen = sizeof(client_server);
- recvfrom(server_socket,buf,sizeof(buf),0,&client_server,&addrlen);
- DEBUG_INFO("buf = %s",buf);
- DEBUG_INFO("recfrom %s:%d -- %s\n",
- inet_ntoa(client_server.sin_addr),
- htons(client_server.sin_port),
- buf);
- addrlen = sizeof(client_server);
- sendto(server_socket,buf,strlen(buf),0,&client_server,addrlen);
- }
-
- sleep(5);
- return 0;
- }
-
修改客户端中的IP地址为192.168.0.11,也就是虚拟机的IP地址
实验解析:
服务器等待接收数据。客户端向服务端发送数据,服务器端接收数据后,将数据原样返回。然后服务端继续等待接收数据。客户端发送完毕后等待接收,接收到数据后睡眠5秒退出程序。
虽然UDP是无连接的,但是connect函数依然有效,它高速操作系统,默认从哪里接收数据,默认向谁发送数据。这样就可以使用read,wirte、send、recv这四个没有指定地址的函数来收发数据了。
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/epoll.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <time.h>
-
- #define _DEBUG_INFO
- #ifdef _DEBUG_INFO
- #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
- ,__FILE__,__func__,__LINE__ \
- , ##__VA_ARGS__)
- #else
- #define DEBUG_INFO(format, ...)
- #endif
-
- int main(int argc, char *argv[])
- {
- int client_socket;
- int res = 0;
- client_socket = socket(AF_INET,SOCK_DGRAM,0);
- DEBUG_INFO("client_socket = %d",client_socket);
-
- struct sockaddr_in remote_addr;
- remote_addr.sin_port = htons(6600);
- remote_addr.sin_family = AF_INET;
- remote_addr.sin_addr.s_addr = inet_addr("192.168.0.11");
- char buf[100];
- snprintf(buf,sizeof(buf),"time=%d",time(NULL));
-
- DEBUG_INFO("remote_addr %s:%d on socket %d\n",
- inet_ntoa(remote_addr.sin_addr),
- htons(remote_addr.sin_port),
- client_socket);
-
- res = connect(client_socket,&remote_addr,sizeof(remote_addr));
- int send_len = send(client_socket,buf,strlen(buf),0);
- memset(buf,0,sizeof(buf));
- int read_len = recv(client_socket,buf,sizeof(buf),0);
-
- DEBUG_INFO("recv %s:%d -- %s\n",
- inet_ntoa(remote_addr.sin_addr),
- htons(remote_addr.sin_port),
- buf);
-
- sleep(5);
- return 0;
- }
测试结果:
如果一个客户端,偶尔也要提供服务的话,那么它绑定(bind)一个明确的本地端口是有必要的,这样别人就知道应该如何主动向它发起通讯了。下面是使用bind绑定本地端口的客户端代码
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/epoll.h>
- #include <errno.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <time.h>
-
- #define _DEBUG_INFO
- #ifdef _DEBUG_INFO
- #define DEBUG_INFO(format, ...) printf("%s:%s:%d -- "format"\n" \
- ,__FILE__,__func__,__LINE__ \
- , ##__VA_ARGS__)
- #else
- #define DEBUG_INFO(format, ...)
- #endif
-
- int main(int argc, char *argv[])
- {
- int client_socket;
- int res = 0;
- client_socket = socket(AF_INET,SOCK_DGRAM,0);
- DEBUG_INFO("client_socket = %d",client_socket);
-
- struct sockaddr_in remote_addr;
- remote_addr.sin_port = htons(6600);
- remote_addr.sin_family = AF_INET;
- remote_addr.sin_addr.s_addr = inet_addr("192.168.0.11");
-
- DEBUG_INFO("INADDR_ANY = %d",INADDR_ANY);
- struct sockaddr_in local_addr;
- local_addr.sin_port = htons(6700);
- local_addr.sin_family = AF_INET;
- local_addr.sin_addr.s_addr = INADDR_ANY;//inet_addr("192.168.0.11");
-
- res = bind(client_socket,(const struct sockaddr *)&local_addr,sizeof(local_addr));
- if(res == -1){
- perror("bind");
- return -1;
- }
-
- char buf[100];
- snprintf(buf,sizeof(buf),"time=%d",time(NULL));
-
- DEBUG_INFO("remote_addr %s:%d on socket %d\n",
- inet_ntoa(remote_addr.sin_addr),
- htons(remote_addr.sin_port),
- client_socket);
-
- res = connect(client_socket,&remote_addr,sizeof(remote_addr));
- int send_len = send(client_socket,buf,strlen(buf),0);
- memset(buf,0,sizeof(buf));
- int read_len = recv(client_socket,buf,sizeof(buf),0);
-
- DEBUG_INFO("recv %s:%d -- %s\n",
- inet_ntoa(remote_addr.sin_addr),
- htons(remote_addr.sin_port),
- buf);
-
- sleep(5);
- return 0;
- }
执行结果:
实验解析:
服务端使用前面的测试代码。这样通讯两端的IP和PORT就都是已知的了,这样比较适合新手,特别是两边都是经验不足的开发人员。防止思维混乱。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。