面向TCP连接的socket通信程序:
服务端:创建套接字,指定协议族(sockaddr_in),绑定,监听(listen),接受链接(accept),发送或接收数据;客户端:创建套接字,指定协议族,连接,发送或接收数据
这几个步骤都是必须的。
补充:在发送和接受数据时:write/send/sendto,read/recv/recvfrom都可以用,通常会用:send,recv;但需要注意的是:在面向UDP的socket程序中,发送数据时,如果用sendto的话,就不用connect了;但是,在面向TCP的程序中,在发送数据时,即使sendto,也必须connect,也就是说connect这一步是必不可少的。
面向UDP连接的socket通信程序:
服务端:创建套接字,指定协议族(sockaddr_in),绑定(不需要listen和accept),发送或接收数据;客户端:创建套接字,指定协议族,连接(和TCP的客户端步骤一样),发送或接收数据。
补充:在发送和接收数据时,和TCP大同小异,write/send/sendto,read/recv/recvfrom都可以用,但UDP通常会用sendto,recvfrom;需要注意的是:当用sendto发送数据的时候,就不用connect了(用了也没事),其他的(write,send)必须connect。
对于已连接udp套接口(调用过connect),与缺省的未连接udp套接口相比,发生了三个变化:
1.不能给输出操作指定目的ip地址和套接口。也就是说,不能使用sendto(),而改写write或send。写到已连接udp套接口上的任何内容都自动发送到connect指定的协议地址。
2.不能使用recvfrom以获悉数据报的发送者,而改用read、recv或recvmsg。在一个已连接udp套接口上由内核为输入操作返回的数据报仅仅是那些来自connect所指定协议地址的数据报。目的地为这个已连接udp套接口的本地协议,发源地却不是该套接口早先connect到的协议地址的数据报,不会投递到该套接口。这样就限制一个已连接udp套接口能且仅能与一个对端交换数据报。
3.由已连接udp套接口引发的异步错误返回给它们所在的进程。相反,未连接udp套接口不接受任何异步错误。
拥有一个已连接udp套接口的进程可为下列两个目的之一再次调用connect:
A.指定新的ip地址和端口号
B.断开套接口。
为了断开一个已连接udp套接口,再次调用connect时把套接口地址结构的地址族成员设置为AF_UNSPEC。这么做可能返回一个EAFNOSUPPORT错误,不过没关系。使得套接口断开连接的是在已连接udp套接口上调用connect的进程。
已连接udp套接口还可用来确定用于某个特定目的地的外出接口。这是有connect函数应用到udp套接口时的一个副作用造成的:内核选择本地ip地址(假设其进程未曾调用bind显式指派它)。这个本地ip地址通过为目的ip地址搜索路由表得到外出接口,然后选用该接口的主ip地址而选定。在udp套接口上调用connect并不给对端主机发送任何信息,它完全是一个本地操作,只是保存对端的ip地址和端口号。在一个未绑定端口号的udp套接口上调用connect同时也给该套接口指派一个临时端口。
阻塞模式补充:
无论是TCP还是UDP,默认情况下创建的都是阻塞模式(blocking)的套接字,执行到accept,connect,write/send/sendto,read/recv/recvfrom等语句时,会一直等待(connect有点例外,它连接一段时间,如果连接不成功,会以错误形式返回,不会一直等待)。
可以把socket设置成非阻塞模式,linux下用fcntl函数,windows下用的是ioctlsocket函数。(TCP和UDP设置成非阻塞模式以后,效果是一样的,都不再等待,而是立即返回。只是sendto和send一次发送的最大数据量可能不同,两种模式下返回的错误代码应该也是相同的)
设置成非阻塞模式以后,这些函数不再等待会立即返回(这和windows下是相同的),至于错误时返回的值应该也是和windows下相同的(具体没试,send和recv在windows错误时返回的值,请看 “套接字的同步阻塞(blocking)与异步非阻塞(no blocking)”)。
TCP面向连接,UDP面向无连接(在默认的阻塞模式下):
read/recv/recvfrom:
当客户端退出程序或断开连接时,TCP的这个函数会立即返回不再阻塞(因为服务端自己知道客户端已经退出或断开连接,证明它是面向连接的),而UDP的这个函数将会始终保持阻塞(因为服务端自己不知道客户端已经退出或断开连接,证明它是面向无连接的)。
TCP无边界,UDP有边界(在默认的阻塞模式下):
read/recv/recvfrom:TCP,客户端连续发送数据,只要服务端的这个函数的缓冲区足够大,会一次性接收过来(客户端是分好几次发过来,是有边界的,而服务端却一次性接收过来,所以证明是无边界的);UDP:客户端连续发送数据,即使服务端的这个函数的缓冲区足够大,也只会一次一次的接收,发送多少次接收多少次(客户端分几次发送过来ÿ