1 概述

TCP和UDP网络编程存在一些本质的差异,主要是由于传输层的差别:UDP是无连接的不可靠的数据报协议,而TCP是面向连接的字节流协议。

下图是典型的UDP客户端和服务器之间的通信流程。客户不与服务器建立连接,而是只管使用sendto函数。服务器不接受来自客户的连接,而是只管调用recvfrom函数,等待某个客户的数据到达。

本章学习用于UDP套接字的两个新函数recvfrom和sendto,并使用UDP重写ECHO程序。还将学习connect函数在UDP套接字中的用法,同时理解异步错误的概念

2 recvfrom和sendto函数

这两个函数类似标准的read、write函数,不过需要额外的三个参数。

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t nbytes, int flags, struct sockaddr *from, socklen_t *addrlen);
ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags, const struct sockaddr *to, socklen_t addrlen);
/*以上函数返回:成功返回读或写到的字节数,出错返回-1*/

前三个参数sockfd、buff和nbytes分别代表:描述符、指向输入或写出缓冲区的指针和读写的字节数。

flags参数在讨论recv、send、recvmsg和sendmsg函数时再介绍,这里默认设置为0。

sendto的to参数指向一个含有数据报接受者的协议地址(IP地址及端口号)的套接字地址结构,其大小由addrlen指定。recvfrom的from参数指向一个含有数据报发送者的协议地址(IP地址及端口号)的套接字地址结构,其大小由addrlen指定。注意sendto的最后一个参数是一个整数值,而recvfrom的最后一个参数是一个指向整形的指针(即值-结果函数)。

写一个长度位(0)的数据报是可行的(TCP不允许),这会发送一个只有IP首部和UDP首部,没有数据的数据报。类似的,recvfrom返回0值也是可以的(TCP则代表对端已关闭连接)。如果recvfrom的from参数是一个空指针,相应的addrlen为0,说明我们不关心发送者的协议地址。recvfrom和sendto函数都可以用于TCP,尽管通常不这么做。

3 最原始的UDP Echo程序

udp_echo_server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h> void echo_server(int sockfd, struct sockaddr *p_client_addr, socklen_t cli_len) { int n;
socklen_t len;
char buf[]; while() {
len = cli_len;
n = recvfrom(sockfd, buf, , , p_client_addr, &len);
sendto(sockfd, buf, n, , p_client_addr, len);
}
} int main(int argc, char **argv) { int sockfd;
struct sockaddr_in server_addr, client_addr; sockfd=socket(AF_INET, SOCK_DGRAM, );
memset(&server_addr, , sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(); if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))<)
perror("bind error!"); echo_server(sockfd, (struct sockaddr *)&client_addr, sizeof(client_addr)); }

该程序存在一些问题:

  1. 函数永远不会终止,因为UDP是一个无连接的协议,没有像TCP中EOF之类的东西
  2. 该函数提供的是一个迭代服务器,而不是并发服务。因此单个服务器进程就得处理所有客户
  3. 对于本套接字,UDP层隐含有排队的发生

udp_echo_client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h> void echo_client(FILE *fp, int sockfd, const struct sockaddr *p_server_addr, socklen_t serv_len) { int n;
char send[], recv[];
while(fgets(send, , fp) !=NULL) {
sendto(sockfd, send, strlen(send), , p_server_addr, serv_len);
n=recvfrom(sockfd, recv, , , NULL, NULL);
recv[n]='\0';
fputs(recv, stdout);
}
} int main(int argc, char **argv) {
int sockfd;
struct sockaddr_in server_addr; if(argc!=) {
printf("usage: udp_client <IP Address>\n");
exit();
} sockfd=socket(AF_INET, SOCK_DGRAM, );
memset(&server_addr, , sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons();
inet_pton(AF_INET, argv[], &server_addr.sin_addr); echo_client(stdin, sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
}

该程序也隐含一个问题:

  1. 客户端尚未请求内核给它的套接字指派一个临时端口
  2. recvfrom第5个和第6个参数是空指针,表示不关心数据是由谁发送。因此任何进程的数据包都会被当成是服务器的应答。
  3. UDP是不可靠的。如果一个数据报丢失,客户将永远阻塞在recvfrom函数上。

假设在服务器不启动的情况下启动客户端,数据报由客户发出,服务器主机响应一个端口不可达的ICMP消息,而这个ICMP消息不返回给客户进程,客户将永远阻塞于recvfrom调用,等待服务器的应答。我们称这个错误为异步错误(asynchronous error)。该错误由sendto引起,但sendto本身却成功返回。UDP输出成功仅仅代表在接口队列中有存放IP数据报的空间。改ICMP直到后来才返回,这就是称其为异步的原因。

4 UDP程序例子小结

UNP学习笔记3——基本UDP套接字编程的更多相关文章

  1. UNP学习笔记1——基本TCP套接字编程

    1 套接字地址结构 大多数套接字函数都需要一个指向套接字地址结构的指针作为参数.每个协议族都定义了自己的套接字结构.这些套接字的结构以sockaddr_开头,以每个协议族唯一的后缀名结尾. 1.1 I ...

  2. 《Unix 网络编程》08:基本UDP套接字编程

    基本UDP套接字编程 系列文章导航:<Unix 网络编程>笔记 UDP 概述 流程图 recvfrom 和 sendto #include <sys/socket.h> ssi ...

  3. 【Python网络编程】利用Python进行TCP、UDP套接字编程

    之前实现了Java版本的TCP和UDP套接字编程的例子,于是决定结合Python的学习做一个Python版本的套接字编程实验. 流程如下: 1.一台客户机从其标准输入(键盘)读入一行字符,并通过其套接 ...

  4. 探索UDP套接字编程

    UDP和TCP处于同一层网络模型中,也就是运输层,基于二者之上的应用有很多,常见的基于TCP的有HTTP.Telnet等,基于UDP有DNS.NFS.SNMP等.UDP是无连接,不可靠的数据协议服务, ...

  5. 【转】 探索UDP套接字编程

    UDP和TCP处于同一层网络模型中,也就是运输层,基于二者之上的应用有很多,常见的基于TCP的有HTTP.Telnet等,基于UDP有DNS.NFS.SNMP等.UDP是无连接,不可靠的数据协议服务, ...

  6. JavaTCP和UDP套接字编程

    在我们刚开始入门Java后端的时候可能你会觉得有点复杂,包含了很多杂七杂八的知识,例如文件上传下载,监听器,JDBC,请求重定向,请求转发等等(当然也没有很多),但是我们自己真正的去开发一个小型网站( ...

  7. 计算机网络实验 UDP套接字编程

    这是个傻瓜式操作教程 西科大计算机网络实验 UDP套接字编程 我用自己的Ubuntu16.04来举例,实验室的是虚拟机,差不多 只针对第三个题目,修改服务器来通过响应客户端发送的GetTime并发送给 ...

  8. UDP套接字编程 返回系统时间

    计算机网络实验 简单UDP套接字编程 这是学校老师自己改进了一点的题目.我预习了好久才搞明白,同学来问的时候,一大堆简单问题实在是不想回答...所以,这时候我觉得博客是个好东西! 我的任务是做客户端和 ...

  9. 【Unix网络编程】chapter8基本UDP套接字编程

    chapter8基本UDP套接字编程 8.1 概述 典型的UDP客户端/服务端的函数调用 8.2 recvfrom和sendto函数 #include <sys/socket.h> ssi ...

随机推荐

  1. Linux VFS分析(二)

    inode的管理:Inode-cache hash表inode_hashtable索引节点缓存 dentry的管理: 我们知道,若干dentry描绘了一个树型的目录结构,这就是用户所看到的目录结构,每 ...

  2. redis 安装成功后外部服务器链接不上

    1.reids服务器的6379端口telnet不通 2. 查看reids进程和端口,都是存在的.只是ip地址是127.0.0.1而不是0.0.0.0,只是本机能使用 3.查找redis的配置文件red ...

  3. 用haproxy实现nginx的proxy_pass转发功能

    公司的网站有个需求,主站点上有两个URL,没有在本地nginx上配置,而是在另一台主机的nginx上配置的站点.如果使用nginx作为反向代理,可以使用proxy_pass指令转发对这两个URL的请求 ...

  4. django视图的定义

    概述 视图:视图的本质就是一个python中的函数,作用是接收web请求,并响应web请求. 过程:django获取浏览器输入的url,经过django中的url管理器匹配到对应的视图函数,视图管理器 ...

  5. 2019-03-28 SQL inner left full

    在使用 join 时,on 和 where 条件的区别如下: 1. on 条件是在生成临时表时使用的条件,它不管 on 中的条件是否为真,都会返回左边表中的记录. 2.where 条件是在临时表生成好 ...

  6. 用户登录记住用户名导致表单自动填充bug解决方法

    最近做项目出现了一个极其讨厌的bug:在用户登录网站时,浏览器会自动提示是否记住密码,当选择记住密码时,正常浏览网页,会发现有那么几个input输入框会自动填充用户名,非常讨厌, 于是就觉得挺简单的一 ...

  7. redis 模拟搭建集群

    一.本文是在一台 linux 系统上,模拟搭建 redis 集群.3 台主机,3 台从机. 二.redis 安装步骤 http://www.cnblogs.com/fangwu/p/8602357.h ...

  8. chrome打开网址但是没有地址栏

    chrome打开网址但是没有地址栏 C:\Users\Administrator>C:\Users\Administrator\AppData\Local\Google\Chrome\Appli ...

  9. Android 自己定义View学习(2)

    上一篇学习了基本使用方法,今天学一下略微复杂一点的.先看一下效果图 为了完毕上面的效果还是要用到上一期开头的四步 1,属性应该要有颜色,要有速度 <?xml version="1.0& ...

  10. Android中的WiFi P2P

    Android中的WiFi P2P可以同意一定范围内的设备通过Wifi直接互连而不必通过热点或互联网. 使用WiFi P2P须要Android API Level >= 14才干够,并且不要忘记 ...