code 见 https://github.com/juniperdiego/Unix-network-programming-of-mine/tree/master/udpserv01

1 建立socket时使用 SOCK_DGRAM 参数,

2 在调用send同函数时 socklen_t addrlen 参数一定要指定对,我刚开始就把addlen赋值成了sizeof(struct sockaddr * )导致错误。

3 注意

in_addr_t inet_addr(const char *cp);

char *inet_ntoa(struct in_addr in);

两个字符串和ip地址转换的参数不一样,一个是in_addr_t, 一个是in_addr

使用方法

inet_ntoa(replyaddr.sin_addr);

servaddr.sin_addr.s_addr = inet_addr(argv[]);

sendto和recvfrom

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,
struct sockaddr *from, socklen_t *addrlen); ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,
const struct sockaddr *to, socklen_t addrlen); 两者均返回:读写字节数——成功,-——出错

此函数需考虑的细节:

(1)首先,该函数永不终止,因为UDP是一个无连接的协议,它没有像TCP中的EOF之类的东西。

(2)其次,该函数提供的是一个迭代服务器(iterative server),而不是像TCP服务器那样可以提供一个并发服务器。一般来说,大多数TCP服务器是并发的,而大多数UDP服务器是迭代的。

对于本套接口,UDP层中隐含有排队发生。事实上,每个UDP套接口都有一个接收缓冲区,到达该套接口的每个数据报都进入这个套接口缓冲区。当进程调用recvfrom时,缓冲区中的下一个数据报以FIFO(先进先出)顺序返回给进程。这样,在进程能够读该套接口中任何已排好队的数据报之前,如果有多个数据报到达该套接口,那么相继到达的数据报仅仅加到该套接口的接收缓冲区中。然而这个缓冲区的大小是有限的。我们可以使用SO_RCVBUF套接口选项来增大它。

下图总结了TCP客户/服务器在两个客户与服务器建立连接时的情形:

如上图所示:服务器主机上有两个已连接套接口,其中每一个都有各自的套接口接收缓冲区。

下图展示了两个客户发送数据报到UDP服务器的情形:

如上图所示,其中只有一个服务器进程,它仅有的单个套接口用于接收所有到达的数据报并发回所有的响应。该套接口有一个接收缓冲区用来存放所有到达的数据报。

对于一个UDP套接口,如果其进程首次调用sendto时它没有绑定一个本地端口,那么内核就在此时为它选择一个临时端口。跟TCP一样,客户可以显示地调用bind,不过很少这样做。

注意 调用recvfrom指定的第5和第6个参数是空指针。这 告知内核我们并不关心应答数据包由谁发送。这样做存在一个风险:任何进程(不论是在于本客户进程相同的主机上还是在不同的主机上)都可以向本客户的IP地址和端口发送数据报,这些数据报将被客户读入并认为是服务器的应答。

[DIEGO] bind 绑定自己的ip和端口,一般由server端调用bind函数,编订自己的监听端口。tcp然后调用listen,变成监听套接字,udp则不调用。

[DIEGO] connect 绑定对端的ip和端口。由于tcp调用connect后,知道对端是谁,所以可以调用read/write/send/receive.

                  UDP 也可以调用connect,指定对端是谁,然后也可以调用read/write/send/receive

TCP调用bind一般如下:

    int                 listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr; listenfd = socket(AF_INET, SOCK_STREAM, ); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); listen(listenfd, LISTENQ);

UDP一般调用如下:

    int                 sockfd/*, connfd*/;
// pid_t childpid;
struct sockaddr_in servaddr; //sockfd = socket(AF_INET, SOCK_STREAM, 0);
sockfd = socket(AF_INET, SOCK_DGRAM, ); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT); bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

UDP的connect调用

我们确实可以给UDP套接口调用connect,但这样做的结果与TCP连接完全不同:它没有三路握手过程。相反,内核只是检查是否存在立即可知的错误,记录对端的IP地址和端口号(取自传递给connect的套接口地址结构),然后立即返回到调用进程。

有了这个能力后,我们必须区分:

未连接UDP套接口(unconnected UDP socket):新创建的UDP套接口缺省如此;

已连接UDP套接口(connected UDP socket):对UDP套接口调用connect的结果。

对于已连接的UDP套接口,与缺省的未连接UDP套接口相比,发生了三个变化:

(1)我们再也不能给输出操作指定宿(目的)IP地址和端口号。也就是说,我们不使用sendto,而改用write或send。写到已连接UDP套接口上的任何内容都自动发送到由connect指定的协议地址(例如IP地址和端口号)。

(2)我们不必使用recvfrom以获悉数据报的发送者,而改用read、recv或recvmsg。在一个已连接UDP套接口上由内核为输入操作返回的数据报仅仅是那些来自connect所指定协议地址的数据报。目的地为这个已连接UDP套接口的 本地协议地址(例如IP地址和端口号),发源地却不是该套接口早先connect到的协议地址的数据报,不会投递到该套接口。这样就限制了一个已连接UDP套接口能且仅能与一个对端交换数据报。

(3)由已连接UDP套接口引发的异步错误返回给它们所在的进程。相反,未连接的UDP套接口不接收任何异步错误。

我们可以说UDP客户进程或服务器进程仅仅在使用自己的UDP套接口与确定的唯一对端进行通信时,才可以调用connect。调用connect的通常是UDP客户,不过有些网络应用中的UDP服务器会与单个客户长时间通信(例如TFTP),这种情况下,客户和服务器都可调用connect。

DNS提供了另一个例子,如下图所示:

通常通过在/etc/resolv.conf文件中列出服务器主机的IP地址,一个DNS客户主机就能被配置成使用一个或多个DNS服务器。如果列出的是单个服务器主机(图中最左边的方框),客户进程就可以调用connect,但是如果列出的是多个服务器主机(图中从右边数第二个方框),客户进程就不能调用connect。另外DNS服务器进程通常处理任何客户请求,因此服务器进程不能调用connect。

给一个UDP套接口多次调用connect

拥有一个已连接UDP套接口的进程可以为下列目的之一再次调用connect:

(1)指定新的IP地址和端口号。对于TCP套接口,connect只能调用一次。

(2)断开套接口。再次调用connect时把套接口地址结构的地址组成员设置为AF_UNSPEC。

性能

当应用进程在一个未连接的UDP套接口上调用sendto时,源自Berkeley的内核暂时连接该套接口,发送数据报,然后断开该连接。在一个未连接的UDP套接口上给两个数据报调用sendto函数于是涉及内核执行下列6个步骤:

(1)连接套接口;

(2)输出第一个数据报;

(3)断开套接口连接;

(4)连接套接口;

(5)输出第二个数据报;

(6)断开套接口连接。

当应用进程知道自己要给同一宿地址发送多个数据报时,显式连接套接口效率更高。调用connect后调用两次write涉及内核执行如下步骤:

(1)连接套接口;

(2)输出第一个数据报;

(3)输出第二个数据报。

unix 网络编程第八章 UDP的更多相关文章

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

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

  2. UNIX网络编程---传输层:TCP、UDP、SCTP(二)

    UNIX网络编程----传输层:TCP.UDP.SCTP 一.概述 本章的焦点是传输层:包括TCP.UDP.和SCTP(流控制传输协议).SCTP是一个较新的协议,最初设计用于跨因特网传输电话信令. ...

  3. UNIX网络编程——UDP 的connect函数(改进版)

    上一篇我们提到,除非套接字已连接,否则异步错误是不会返回到UDP套接字的.我们确实可以给UDP套接字调用connect,然而这样做的结果却与TCP连接大相径庭:没有三次握手.内核只是检查是否存在立即可 ...

  4. UNIX网络编程——getsockname和getpeername函数

    UNIX网络编程--getsockname和getpeername函数   来源:网络转载   http://www.educity.cn/linux/1241293.html     这两个函数或者 ...

  5. 网游中的网络编程3:在UDP上建立虚拟连接

    目录 网游中的网络编程系列1:UDP vs. TCP 网游中的网络编程2:发送和接收数据包 网游中的网络编程3:在UDP上建立虚拟连接 TODO 二.在UDP上建立虚拟连接 介绍 UDP是无连接的,一 ...

  6. Unix网络编程--卷一:套接字联网API

    UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...

  7. [转载] 读《UNIX网络编程 卷1:套接字联网API》

    原文: http://cstdlib.com/tech/2014/10/09/read-unix-network-programming-1/ 文章写的很清楚, 适合初学者 最近看了<UNIX网 ...

  8. UNIX网络编程---简介

    UNIX网络编程---简介 一.           概述 a)       在编写与计算机通信的程序时,首先要确定的就是和计算机通信的协议,从高层次来确定通信由哪个程序发起以及响应在合适产生.大多数 ...

  9. UNIX网络编程中的需要注意的问题

    字节流套接字上调用read或write,输入或输出的字节数可能比请求的数量少,这个现象的原因在于内核中用于套接字的缓冲区可能已经达到了极限.此时所需要的是调用者再次调用read或write函数.这个现 ...

随机推荐

  1. php上传中文文件文件名乱码问题

    php上传文件是最最基础的一个技术点,但是深入进去也有不少问题需要解决,这不,上传中文文件后,文件名变成了乱码. 下面是问题代码,很简单: 1.问题代码 html部分: <html> &l ...

  2. PHP -- 配置Apache遇到的问题

    在本地电脑用XAMPP+php+mysql配置项目的时候,能够正常运行. 但是通过远程进入VPN配置的时候,配置方式一样,但是老是无法显示. 后来看了错误日志后,发现之前在没完全配置完的时候运行,生成 ...

  3. PAT甲级1033. To Fill or Not to Fill

    PAT甲级1033. To Fill or Not to Fill 题意: 有了高速公路,从杭州到任何其他城市开车很容易.但由于一辆汽车的坦克容量有限,我们不得不在不时地找到加油站.不同的加油站可能会 ...

  4. iOS 反反注入 修改__RESTRICT,__restrict工具

    通过在 Xcode 里的 Other Linker Flags 设置参数,可以防止App被注入dylib(仅限于iOS 10 以下系统)  比如,某艺,XX音乐等 dylib无法注入,也就意味着没办法 ...

  5. GIT 提交步骤

    1.提交 git add .

  6. Intelij Idea下的git使用

    一.简介 在我们入门软件研发并且是团队开发的时候,总会遇到这样合代码这么简单粗暴的工作,最开始我也能体会到这项工作折磨.那git是干什么得呢?简称分布式版本控制系统,常见就是上传代码.整合代码.更新代 ...

  7. Chrome无法播放m3u8格式的直播视频流的问题解决

    出国,然后安装这个插件即可:Native HLS Playback https://chrome.google.com/webstore/detail/native-hls-playback/emnp ...

  8. How to implement *All-Digital* analog-to-digital converters in FPGAs and ASICs

    When we engineers look at the complexity of system design these days, we are challenged with crammin ...

  9. Maven:Generating Project in Batch mode 卡住问题

    Maven命令执行到Generating Project in Batch mode 卡住,原因是网络带宽不足问题!需要下载一个约4.1M的archetype-catalog.xml文件. Maven ...

  10. 【QQ输入法】QQ输入法输入的英文字母顺便空格很大

    正常的输入出来是这个样子的: 现在变成了这个样子: 怎么解决这个问题呢: 快捷键 shift+空格   即可解决