UDP属于非连接传输,因此不需要进行连接操作,直接可根据IP地址与端口发送数据
服务器端:
char buf[1024]; int i=0; int fd = socket(AF_INET,SOCK_DGRAM,0); struct sockaddr_in dest_addr; bzero(&dest_addr,sizeof(dest_addr)); socklen_t addrlen; dest_addr.sin_family=AF_INET; dest_addr.sin_port=htons(10000); dest_addr.sin_addr.s_addr=INADDR_ANY; bind(fd,(struct sockaddr*)&dest_addr,sizeof(dest_addr)); while (1) { i++; int ret = recvfrom(fd, buf, 1024, 0,(struct sockaddr*) &dest_addr, &addrlen); if(ret < 0){ perror("recvfrom"); break; } printf ("%s,%d ", inet_ntoa (dest_addr.sin_addr), i); //获得地址dest_addr后,可用sendto向服务器发送数据 } printf ("%s,%d ", inet_ntoa (dest_addr.sin_addr), i);
服务器必须有固定的IP已经端口,因此必须使用bind函数把自身的套接字与固定端口绑定。
由于服务器无法得知客户的IP以及端口,因此服务器必须首先使用UDP接收函数recvfrom()等待客户端发送数据。当客户端的数据到达后,客户端的地址信息被记录与dest_addr中,此时便可对客户传输数据
客户端:
char buf[1024]; int i=0; struct sockaddr_in dest_addr; int sockfd = socket(AF_INET,SOCK_DGRAM,0); int len = sizeof(buf); bzero(&dest_addr,sizeof(dest_addr)); dest_addr.sin_family=AF_INET; dest_addr.sin_port=htons(10000); dest_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); connect(sockfd,(struct sockaddr *)&dest_addr, sizeof(dest_addr));//如不连接,则系统为客户端随机分配端口 while(i<10000) { i++; int ret = sendto(sockfd, buf, len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); if (ret < 0) { perror("write error"); break; } } printf("send number:%d ",i);
客户端必须事先知道服务器的IP地址以及端口,才能使用UDP函数sento()对服务器发送数据。
客户端不需绑定端口。如不适用connect()和bind()函数,则系统自动给客户端随机分配一个端口作为发送端口使用,每次发送都使用不同的端口。如使用connect()设置后,则使用固定的端口发送数据。
聊天室:不分服务器端和客户端,只需指明对方的IP和端口就可以聊天。
#include <arpa/inet.h> #include <stdio.h> #include <string.h> #include <netinet/in.h> #include "pthread.h" char buf[1024]; int fd; //thread for receive msg void* receiver(void* p){ struct sockaddr_in dest_addr; int addrlen; while (1) { int ret = recvfrom(fd, buf, 1024, 0,(struct sockaddr*) &dest_addr, &addrlen); if(ret < 0) { perror("recvfrom"); break; } printf ("from %s:%d ", inet_ntoa (dest_addr.sin_addr),ntohs(dest_addr.sin_port)); printf("%s ",buf); } } //main thread for send msg int main(int argc,char **argv) { if(argc!=4){ printf("usage:order IP port_dest port_local "); return 0; } char buf[1024]; fd = socket(AF_INET,SOCK_DGRAM,0); struct sockaddr_in dest_addr,my_addr; bzero(&dest_addr,sizeof(dest_addr)); socklen_t addrlen; dest_addr.sin_family=AF_INET; dest_addr.sin_port=htons(atoi(argv[2])); dest_addr.sin_addr.s_addr=inet_addr(argv[1]); bzero(&my_addr,sizeof(my_addr)); my_addr.sin_family=AF_INET; my_addr.sin_port=htons(atoi(argv[3])); my_addr.sin_addr.s_addr=INADDR_ANY; bind(fd,(struct sockaddr*)&my_addr,sizeof(my_addr)); //init the thread pthread_t receiver_thread; if(0!=pthread_create(&receiver_thread, NULL, receiver, NULL)) printf("create thread failed "); while (1) { gets(buf); if(0==strcmp(buf,"exit")){ close(receiver_thread); break; } int ret = sendto(fd, buf, 1024, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); if (ret < 0){ perror("write error"); break; } } }
通过写聊天室程序加深了对sendto和recvfrom两个UDP函数用法的理解。
sendto(fd, buf, 1024, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));fd是自己的套接字,而不是发送目标的套接字。fd通过connect()或bind()可以与端口绑定,从而使用固定端口发送数据。如不适用此二函数,则使用随机端口发送。只要dest_addr正确设置了接受方的IP地址以及端口,即可发送数据。
recvfrom(fd, buf, 1024, 0,(struct sockaddr*) &dest_addr, &addrlen);fd也是自己的套接字,不是接收方的套接字。也不需要事先设置接收方的地址就可以接受所有发送给自己的信息,dest_addr只是在接收到数据后记录发送方的地址而已。