socket编程与线程模型三
2、socket详解
socket是一种特殊的I/O,所以socket类似于文件指针、文件句柄。通过socket可以写入和读取数据。socket原理图
socket这种I/O的特殊性在于创建了一个socket以后并不能马上进行数据读取或者写入操作。它必须和一定的地址联系起来才可以操作。从无连接的协议看看这个过程。
首先是数据的接受方创建一个socket,然后把一个地址SockAddr1与这个特殊的I/O绑定。然后就可以从这个socket进行数据读取:recvfrom()。这个一般是服务器方。
然后是客户端方面,它显然必须知道服务器端的SockAddr1这个地址才能写入数据。所以,它创建一个特殊的I/O --- socket,然后就进行数据写入:sendto()。这个时候sendto除了向指定的地址写入数据,还要隐式的给这个socket绑定一个本地地址:SockAddr2。
服务方通过recvfrom()除了读取到客户提供的数据以外,还可以通过出口参数获得发送者的地址。它使用sendto(),通过任何一个socket(用socket2或者新建一个,新建是浪费资源,就用socket2就可以了)向客户端回写一些数据。
上述情况时客户端给新建的socket通过sendto()隐式绑定地址,这个地址是系统随机生成的。客户端也可以在sendto()之前采用bind()显式绑定一个地址,然后sendto()就会采用这个显式绑定的地址作为源地址,但是不鼓励这么做。
总结:socket是一种特殊的I/O,通过这种I/O可以读写数据。Socket在使用的时候需要绑定一个地址,这个被绑定的地址就是应用程序用来读取的地址,也就是接收数据的地址。而应用程序写入数据的地址,也就是发送数据的地址并不是和socket需要绑定的,这个地址可以随意变换。所以,在无连接情况下,通过同一个socket可以向多个地址写入数据,但是读取数据的地址只有一个,那就是给这个socket绑定的地址。
无连接多点通信
上图所示的例子我们可以认为上方为服务器。服务器创建soctet1,然后与地址SockAddr2显式绑扎。所以,SockAddr2就是服务器从socket1读取数据的地址,只有一个读取地址。
然后,3个客户端知道服务器地址SockAddr2,它们向服务器写入数据,sendto()。然后,服务器通过recvfrom()获取数据,并且获知三个客户端的绑扎地址(隐式或者显式都可以)。服务器通过三个客户端的地址,通过同一个socket--- socket1,向三个客户端分别写入数据。客户端通过recvfrom()得到服务器数据。
对于一个socket,只能进行一次地址绑扎,即一次bind()。假如把上图认为是一个客户端向三个服务器首先进行sendto()写入数据,客户端并没有显式绑扎SockAddr2地址,那么客户端第一次调用sendto()的时候就会进行隐式绑扎,以后就不会。第一次绑扎分配的SockAddr2不会再改变,三个服务器通过recvfrom()获取到的源地址都是SockAddr2。
广播:从以上原理,可以知道无连接协议的广播是socket的发送地址的一个特例,而与绑定地址和函数没有关系。只要设置sendto()的目的地址SockAddr为广播类型就可以了。