UDP套接字的使用介绍
2016-05-05 21:44
309 查看
UDP套接字相比于TCP套接字具有不同的特征。
1、UDP套接字在使用之前不需要进行连接,即对应于客户端不需要进行connect,创建socket之后直接发送信息;服务器在绑定IP和端口之后在循环中不需要accept进行阻塞,直接利用接收函数阻塞接收信息,并且在完成通讯之后不需要进行close;
2、UDP是尽力而为的通信。
3、在发送的时候UDP需要指定一个比较合适的缓冲大小,不然超过缓冲的将会被丢弃。
4、UDP发送数据的时候采用的sento()和recvfrom()函数,而不是send()和recv()。
下面的例子中,客户端将发送一段字节,发送给服务器后,服务器将这些字节原封不动的返回给客户端,客户端回显。
1、UDP套接字在使用之前不需要进行连接,即对应于客户端不需要进行connect,创建socket之后直接发送信息;服务器在绑定IP和端口之后在循环中不需要accept进行阻塞,直接利用接收函数阻塞接收信息,并且在完成通讯之后不需要进行close;
2、UDP是尽力而为的通信。
3、在发送的时候UDP需要指定一个比较合适的缓冲大小,不然超过缓冲的将会被丢弃。
4、UDP发送数据的时候采用的sento()和recvfrom()函数,而不是send()和recv()。
UDP发送和接收数据的函数 /** * socket:套接字fd * msg:指向要发送的字节序列 * msgLength:要发送的字节序列的长度 * flag: * flags取值有: * 0: 与write()无异 * MSG_DONTROUTE:告诉内核,目标主机在本地网络,不用查路由表 * MSG_OOB:指明发送的是带外信息 * destAddr:指向要发送的目的地址的sockaddr的指针 * addrLen:地址信息的长度 **/ ssize_t sendto(int socket, const void *msg, size_t msgLength, int flag, const struct sockaddr *destAddr, socklen_t addrLen); /** * 前四个参数和sendto()一样 * msg:要保存的字节序的位置 * flags取值有: * 0:常规操作,与read()相同 * MSG_OOB:指明发送的是带外信息 * MSG_PEEK:可以查看可读的信息,在接收数据后不会将这些数据丢失 * srcAddr:通过这个指针可以得到send的客户端的地址 * addrLen:地址结构的长度 **/ ssize_t recvfrom((int socket, const void *msg, size_t msgLength, int flag, const struct sockaddr *srcAddr, socklen_t addrLen); 以上两个函数的返回值分别为发送/接收的数据的字节数; 并且以上两个函数需要注意的部分是指定了msg的长度之后,就只会发送或者接收那么多,剩下的就会被丢弃。
下面的例子中,客户端将发送一段字节,发送给服务器后,服务器将这些字节原封不动的返回给客户端,客户端回显。
客户端代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netdb.h> int main(int argc, char *argv[]) { //test argument num if(argc < 3 || argc > 4) { printf("<server address/name> <echo word> [derver port/service]\n"); exit(1); } char *server = argv[1]; char *echoString = argv[2]; size_t echoStringLen = strlen(echoString); //Third argument char *servPort = (argc == 4) ? argv[4] : "echo"; //通过设置addrinfo结构体告诉系统我们需要什么样的地址 struct addrinfo addrKind; memset(&addrKind, 0, sizeof(addrKind)); //结构体置0 addrKind.ai_family = AF_UNSPEC; //任何地址族都可以 addrKind.ai_socktype = SOCK_DGRAM; //只接受UDP报文 addrKind.ai_protocol = IPPROTO_UDP; //协议采用UDP //其他没有设置的字段都为0 //通过getaddrinfo函数得到地址 struct addrinfo *servAddr; //解析的服务器的地址链表 int rtnVal = getaddrinfo(serve, servPort, &addrKind, &servAddr); if(rtnVal != 0) { printf("%s\n", gai_strerror(rtnVal)); //利用gai_strerror()函数获取错误信息 exit(1); } //我们根据UDP的信息,创建UDP套接字 int sock = socket(servAddr->ai_family, servAddr->ai_socktype, servAddr->ai_protocol); //创建UDP套接字 if(sock < 0) { printf("socket() error\n"); exit(1); } //创建UDP套接字之后直接发送数据,不需要进行connect连接 //由于之前已经知道了服务器的地址,直接向这个地址发送数据 ssize_t numBytes = sendto(sock, echoString, echoStringLen, 0,servAddr->ai_addr, servAddr->ai_addrlen); if(numBytes < 0 || numBytes != echoStringLen) { printf("sendto() error\n"); exit(1); } //发送完了,现在我们需要接受一个服务器发来的回应 struct sockaddr fromAddr; socklen_t fromAddrLen = sizeof(sockaddr); char buffer[MAXSIZE + 1]; numBytes = recvfrom(sock, buffer, MAXSIZE, 0, &fromAddr, &fromAddrLen); if(numBytes < 0 || numBytes != echoStringLen) { printf("recvfrom() error\n"); exit(1); } //接下来需要比较主动发送的服务器地址和recvfrom的地址是不是一样 //暂时用一个没有实现的函数进行表示 if(!SockAddrsEqual(servAddr->ai_addr, fromAddr)) { printf("received package from unknow source\n"); exit(1); } freeaddrinfo(servAddr); //销毁地址链表 buffer[echoStringLen] = '\0'; printf("received: %s\n", buffer); close(sock); exit(0); }
服务器代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netdb.h> int main(int argc, char *argv[]) { if(argc != 2) { printf("argument need <server port>\n"); exit(1); } char *service = argv[1]; //构建addrinfo用来解析服务器的地址 struct addrinfo addrKind; memset(&addrKind, 0, sizeof(addrKind)); //结构体置0 addrKind.ai_family = AF_UNSPEC; //任何地址族都可以 addrKind.ar_flags = AI_PASSIVE; //可以接受任何地址 addrKind.ai_socktype = SOCK_DGRAM; //只接受UDP报文 addrKind.ai_protocol = IPPROTO_UDP; //协议采用UDP //其他没有设置的字段都为0 struct addrinfo *servAddr; //解析的服务器的地址链表 int rtnVal = getaddrinfo(NULL, service, &addrKind, &servAddr); //获取服务器的地址,因为后面需要绑定服务器的地址和端口 if(rtnVal != 0) { printf("%s\n", gai_strerror(rtnVal)); //利用gai_strerror()函数获取错误信息 exit(1); } int sock = socket(servAddr->ai_family, servAddr->ai_socktype, servAddr->ai_protocol); //创建UDP套接字 if(sock < 0) { printf("socket() error\n"); exit(1); } //绑定本地的地址和端口 if(bind(sock, servAddr->ai_addr, servAddr->ai_addrlen) < 0) { printf("bind() error\n"); exit(1); } freeaddrinfo(servAddr); //销毁地址链表 for(; ;) //服务器一直循环接收 { struct sockaddr clntAddr; socklen_t clntAddrLen = sizeof(sockaddr); //阻塞,接收客户端的信息 char buffer[MAXSIZE + 1]; ssize_t recenumBytes = recvfrom(sock, buffer, MAXSIZE, 0, &clntAddr, &clntAddrLen); if(recenumBytes < 0) { printf("recvfrom() error\n"); exit(1); } //接收到了,将该信息发送给客户端 ssize_t sendnumBytes = sendto(sock, buffer, numBytes, 0, clntAddr, clntAddrLen); if(sendnumBytes < 0 || sendnumBytes != recenumBytes) { printf("sendto() error\n"); exit(1); } } }
相关文章推荐
- C#基于UDP实现的P2P语音聊天工具
- Lua下基本的网络编程示例
- C#基于UDP进行异步通信的方法
- 距离详解Linux下的UDP方式通讯
- linux网络编程用到的网络函数详解用和使用示例
- C#网络编程基础之进程和线程详解
- C++ 网络编程 总结
- C#中使用UDP通信实例
- Linux网络编程之UDP Socket程序示例
- 服务器 UDP端口占用几千个的解决办法
- Android网络编程之UDP通信模型实例
- udp socket客户端和udp服务端程序示例分享
- 谈谈新手如何学习PHP网络编程第1/2页
- Python 网络编程起步(Socket发送消息)
- java必学必会之网络编程
- c# socket网络编程接收发送数据示例代码
- PHP的Socket通信之UDP通信实例
- NodeJS学习笔记之网络编程
- linux网络编程----->高并发--->epoll多路I/O转接服务器