第八章 基本UDP套接字编程

//1.
典型的UDP客户/服务器程序:客户不与服务器建立连接,而只管使用 sendto 给服务器发送数据报,其中必须指定目的地(即服务器地址)。类似的,服务器不接受来自客户端的连接,
而只管调用 recvfrom 函数,等待来自某个客户的数据的到达。 recvfrom 将与接收的数据一起返回客户的协议地址。


//2.
写一个长度为0的数据报是可以的,在UDP情况下,会形成一个只包含IP首部和UDP首部而没有数据的IP数据报。这也意味着对于数据报协议, recvfrom 函数返回0是可以接受的(sendto 长度0 时,对应的recvfrom确实会返回0),
他并不像TCP套接字上 recv 返回0表示对端已经关闭。既然UDP是无连接的,因此也没有诸如关闭UDP连接之类的事情。

如果 recvfrom 的 最后第二个参数为空,则其最后一个参数也应该为空,代表我们不关心数据发送端的地址
recvfrom 和 sendto 都可以应用于 TCP 服务,尽管通常没有这么做的理由


//3.
对于UDP套接字,UDP层隐含有排队发生,事实上每个UDP套接字都有一个接收缓冲区,到达该套接字的每个数据报都进入这个套接字缓冲区,当进程调用 recvfrom 时候,缓冲区中
的下一个数据以 FIFO(先进先出) 顺序返回给进程


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


//5.
UDP单播:在客户主机能够与服务器主机发送数据报前,需要一次ARP请求与应答的交换


//6.
一个基本规则:对于UDP套接字,由他引发的异步错误将不会返回给他,除非他已连接


//7.
客户必须给 sendto 调用指定服务器Ip和Port。一般来说,客户的Ip和Port由内核去指定,并且客户的临时端口一旦确定将不可更改,然而客户的Ip地址确可以随着客户发送的每个数据报进行更改
如果客户捆绑了一个Ip地址到其套接字上,但是内核决定外出数据必须从另一个数据链路发出,这个时候Ip数据报将包含一个不同于外出链路Ip地址的源Ip地址


//8.
UDP的 connect 没有三路握手功能,内核只检查是否存在立刻可知的错误(例如一个明显不可达的目的地)
未连接的 UDP 套接字:新创建的UDP套接字默认如此
已连接的 UDP 套接字:对UDP套接字调用 connect 的结果
对于已连接的 UDP 套接字,发生了三个变化:
(A):我们再也不能给输入输出操作指定目的地IP地址和端口号了,写到已连接套接字上的套接字的任何内容都会自动发送到由 connect 指定的协议地址上
(B):只能与一个Ip地址交换数据报
(C):由已连接UDP套接字引发的异步错误,会立刻返回给他们所在的进程(并非所有的系统都实现了该功能,win7下测试发现,已连接的UDP的sendto一个不可达地址也不会产生错误)

TCP和UDP套接字的输入输出操作:


备注:
在win7下测试发现:已连接的 udp socket 仍可以使用指定地址的 sendto 向其他地址发送数据

connect 文档:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx

The connect function is used to create a connection to the specified destination. If socket s, is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound.
For connection-oriented sockets (for example, type SOCK_STREAM), an active connection is initiated to the foreign host using name (an address in the namespace of the socket; for a detailed description, 
see bind and sockaddr).
Note  If a socket is opened, a setsockopt call is made, and then a sendto call is made, Windows Sockets performs an implicit bind function call.

When the socket call completes successfully, the socket is ready to send and receive data. If the address member of the structure specified by the name parameter is filled with zeros, 
connect will return the error WSAEADDRNOTAVAIL. 
Any attempt to reconnect an active connection will fail with the error code WSAEISCONN.
For connection-oriented, nonblocking sockets, it is often not possible to complete the connection immediately. In such a case, this function returns the error WSAEWOULDBLOCK. However, the operation proceeds.
When the success or failure outcome becomes known, it may be reported in one of two ways, depending on how the client registers for notification.
If the client uses the select function, success is reported in the writefds set and failure is reported in the exceptfds set.
If the client uses the functions WSAAsyncSelect or WSAEventSelect, the notification is announced with FD_CONNECT and the error code associated with the FD_CONNECT indicates either success or a specific reason for failure.
For a connectionless socket (for example, type SOCK_DGRAM), the operation performed by connect is merely to establish a default destination address that can be used on subsequent send/ WSASend and recv/ WSARecv calls. 
Any datagrams received from an address other than the destination address specified will be discarded. If the address member of the structure specified by name is filled with zeros, the socket will be disconnected. 
Then, the default remote address will be indeterminate, so send/ WSASend and recv/ WSARecv calls will return the error code WSAENOTCONN. However, sendto/ WSASendTo and recvfrom/ WSARecvFrom can still be used. 
The default destination can be changed by simply calling connect again, even if the socket is already connected. Any datagrams queued for receipt are discarded if name is different from the previous connect.
For connectionless sockets, name can indicate any valid address, including a broadcast address. However, to connect to a broadcast address, a socket must use setsockopt to enable the SO_BROADCAST option. Otherwise,
connect will fail with the error code WSAEACCES.
When a connection between sockets is broken, the socket that was connected should be discarded and new socket should be created. When a problem develops on a connected socket, 
the application must discard the socket and create the socket again in order to return to a stable point.
Note  When issuing a blocking Winsock call such as connect, Winsock may need to wait for a network event before the call can complete. Winsock performs an alertable wait in this situation, 
which can be interrupted by an asynchronous procedure call (APC) scheduled on the same thread.
Issuing another blocking Winsock call inside an APC that interrupted an ongoing blocking Winsock call on the same thread will lead to undefined behavior, and must never be attempted by Winsock clients.


//9.
拥有一个已连接UDP套接字的进程可以出于以下两个目的再次调用 connect
(A):指定新的Ip和端口号
(B):断开套接字
为了断开一个UDP套接字连接,我们再次调用 connect 时,把套接字地址结构的地址族成员设置为 AF_UNSPEC ,并将清零的地址传入
为UDP套接字指定 connect ,一般会提高 sendto 效率

已连接UDP套接字还可以用于确定用于某个特地目的地的外出接口。这是由 connect 函数应用到 UDP 套接字的一个副作用造成的:
内核选择本地Ip地址(假使进程尚未显示调用 bind )。
在一个尚未绑定端口号的UDP套接字上调用 connect 同事也给该套接字指定了一个临时端口


//10.
TCP 和 UDP 端口是相互独立的
原文地址:https://www.cnblogs.com/szn409/p/8024850.html