技术分析:基本 UDP 套接字编程(1)
技术分析:基本 UDP 套接字编程(1)
UDP 协议和 TCP 协议不同,它是一种面向无连接、不可靠的传输层协议。在基于 UDP 套接字编程中,数据传输可用函数 sendto 和 recvfrom。以下是基本 UDP 套接字编程过程:
sendto 与 recvfrom 函数
这两个函数的功能类似于 write 和 read 函数,可用无连接的套接字编程。其定义如下:
- /* 函数功能:发送数据;
- * 返回值:若成功则返回已发送的字节数,若出错则返回-1;
- * 函数原型:
- */
- #include <sys/socket.h>
- ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags,
- const struct sockaddr *destaddr, socklen_t addrlen);
- /* 说明:
- * 该函数功能类似于write函数,除了有标识符flags和目的地址信息之外,其他参数一样;
- *
- * flags标识符取值如下:
- * 1)MSG_DONTROUTE 勿将数据路由出本地网络
- * 2)MSG_DONTWAIT 允许非阻塞操作
- * 3)MSG_EOR 如果协议支持,此为记录结束
- * 4)MSG_OOB 如果协议支持,发送带外数据
- *
- * 若sendto成功,则只是表示已将数据无错误的发送到网络,并不能保证正确到达对端;
- * 该函数通过指定目标地址允许在无连接的套接字之间发送数据例如UDP套接字);
- */
- /* 函数功能:接收数据;
- * 返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0,若出错则返回-1;
- * 函数原型:
- */
- #include <sys/socket.h>
- ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,
- struct sockaddr *addr, socklen_t *addrlen);
- /* 说明:
- * 该函数功能与read类似;
- * 若addr为非空时,它将包含数据发送者的套接字地址;
- *
- * flags标识符取值如下:
- * 1)MSG_WAITALL 等待所有数据可用
- * 2)MSG_DONTWAIT 允许非阻塞操作
- * 3)MSG_PEEK 查看已读取的数据
- * 4)MSG_OOB 如果协议支持,发送带外数据
- */
基于 UDP 套接字编程
下面我们使用 UDP 协议实现简单的功能,客户端从标准输入读取数据并把它发送给服务器,服务器接收到数据并把该数据回射给客户端,然后客户端收到从服务器回射的数据把它显示到标准输出。其功能实现如下图所示:
服务器程序
- /* UDP 服务器 */
- #include <string.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #define SERV_PORT 9877 /* 通用端口号 */
- extern void err_sys(const char *, ...);
- extern void dg_echo(int sockfd, struct sockaddr *addr, socklen_t addrlen);
- int main(int argc, char **argv)
- {
- int sockfd;
- int err;
- struct sockaddr_in servaddr, cliaddr;
- /* 初始化服务器地址信息 */
- bzero(&servaddr, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(SERV_PORT);
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- /* 创建套接字,并将服务器地址绑定到该套接字上 */
- if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- err_sys("socket error");
- err =bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
- if(err < 0)
- err_sys("bind error");
- /* 服务器处理函数:读取套接字文本行,并把它回射给客户端 */
- dg_echo(sockfd, (struct sockaddr*) &cliaddr, sizeof(cliaddr));
- }
处理函数
- #include "unp.h"
- void
- dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen)
- {
- int n;
- socklen_t len;
- char mesg[MAXLINE];
- for ( ; ; ) {
- len = clilen;
- n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
- Sendto(sockfd, mesg, n, 0, pcliaddr, len);
- }
- }
评论暂时关闭