首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

面向连接的通讯和无连接的通信

2013-10-27 
面向连接的通信和无连接的通信1.面向连接的通信在IP中,面向连接的通信时通过TCP/IP协议来实现的。应用程序

面向连接的通信和无连接的通信

1.面向连接的通信

在IP中,面向连接的通信时通过TCP/IP协议来实现的。应用程序在使用TCP通信时,需要建立一个虚拟连接。其模型如下:

面向连接的通讯和无连接的通信

服务器端

一旦为协议创建了套接字,就要将套接字绑定到一个已知地址上,用bind函数来实现。其定义如下:

int bind(   SOCKET      s,   const struct sockaddr FAR *name,   int namelen);
s:为要连接的套接字。name:其为类型为struct sockaddr。对于TCP协议要用结构体SOCKADDR_IN,要将该结构体转换为该类型。namelen:表示要传递的、由协议决定的地址结构的长度,即第二个参数的长度。

 当将套接字绑定后,就是将套接字置于监听状态,函数为listen。其定义如下:

int listen(   SOCKET s,   int    backlog);
s:其为绑定的套接字。backlog:表示等待连接队列的最大长度。当服务器接受了一个连接,就将该连接请求从该队列中删除;当连接请求超过队列长度,就会发回WSAECONNREFUSED错误。

为了接受连接请求,要使用函数accept、WSAAccept或AcceptEx来实现。其中accept函数定义如下:

SOCKET accept(     SOCKET   s,     struct sockaddr FAR* addr,     int FAR* addrlen);
s:为绑定的套接字。addr:为TCP应该是一个有效的SOCKADDR_IN的地址,如果是其他协议就应该是相应的SOCKADDR结构。addr:为SOCKADDR_IN结构体的长度。返回值:其返回一个新的套接字描述符,其后与客服端的所有操作都应该使用该新的套接字。

通过accept函数,可以讲等待连接队列的第一个请求提供服务。accept返回后,addr会被相应的对方的IP4信息填充。
客户端

客户端创建需要下面3个步骤:

1)创建一个套接字。2)建立一个SOCKADDR地址结构。其为服务器的IP地址和端口号。3)用connect或WSAConnect函数来与服务器建立连接。

连接套接字通过函数conenct、WSAConnect或ConnectEx来完成。其中connect函数的定义如下:

int connect(    SOCKET s,    const struct sockaddr FAR* name,    int namelen);
s:为创建的套接字。name:是TCP的套接字地址结构SOCKADDR_IN,其为要连接的服务器。namelen:为name的长度。

数据传输

要在已建立的套接字上发送数据,可以使用两个函数:send和WSASend。其中send函数的定义如下:

int send(    SOCKET s,    const char FAR* buf,    int len,    int flags);
s:为已建立的、用于发送数据的套接字。buf:其为指向字符的缓冲区,其为要发送的数据。len:指向发送的缓冲区的字符数,即要发送的数据长度。flags:可为0、MSG_DONTROUTE、MSG_OOB(紧急数据)。支持“或”运算。返回值:执行成功返回发送的字节数,执行错误返回SOCKET_ERROR。

Send API的Winsock 2版本的函数为WSASend,其定义如下:

int WSASend(    SOCKET s.    LPWSABUF lpBuffers,    DWORD dwBufferCount,    LPDWORD lpNumberOfByteSent,    DWORD dwFlags,    LPWSAOVERLAPPED lpOverlapped,    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
 s:为准备发送数据的套接字。lpBuffers:指向一个或多个WSABUF结构的指针。既可以是一个独立的结构,也可以是一个结构数组。ldwBufferCount:传递的WSABUF结构的数量。lpNumberOfByteSent:其为已经发送了的字节数。dwFlags:其可为为MSG_PEEK、MSG_OOB和MSG_PARTIAL,支持“或”运算。lpOverlapped和lpCompletionRoutine:用于重叠I/O。返回值:执行成功返回0;失败返回SOCK_ERROR。

        一个特殊的传输函数,该函数起初将套接字置于关闭状态,并发送断开的数据。只适用于从容关机和断开数据的传输协议。该函数的行为与利用SD_SEND参数调用shutdown函数差不多,但它还要发送参数boundDisconnectData中的数据。之后发送禁止在该套接字上进行。发送失败发挥SOCKET_ERROR。该函数为WSASendDisconnect。其定义如下:

int WSASendDisconnect(   SOCKET s,   LPWSABUF  lpOutboundDisconnectData);

 

在已经连接的套接字上接收数据,有三个函数recv、WSARecv和WSARecvDisconnect。其中recv函数的定义如下:

int recv(   SOCKET s,   char FAR *buf,   int len,   int flags);
s:为准备接收数据的套接字。buf:用于接收数据的缓冲区。len:准备接收的字节数或buf缓冲区的长度。flags:与send函数相同:0、MSG_PEEK、MSG_OOB。其中0表示什么行为;MSG_PEEK表示将可用数据复制到用户缓冲区中,但不从系统的缓冲区中删除。返回值:返回获取的数据字节数。

WSARecv函数在recv函数的基础上增加了一些新特性,如重叠I/O和部分数据报通知。其定义如下:

int WSARecv(    SOCKET s.    LPWSABUF lpBuffers,    DWORD dwBufferCount,    LPDWORD lpNumberOfByteRecvd,    DWORD dwFlags,    LPWSAOVERLAPPED lpOverlapped,    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
s:为准备接收数据的套接字。lpBuffers:指向一个或多个WSABUF结构的指针。既可以是一个独立的结构,也可以是一个结构数组。ldwBufferCount:传递的WSABUF结构的数量。lpNumberOfByteRecvd:其为已经接收到的字节数。dwFlags:其可为为MSG_PEEK、MSG_OOB和MSG_PARTIAL,支持“或”运算。lpOverlapped和lpCompletionRoutine:用于重叠I/O。返回值:执行成功返回0;失败返回SOCK_ERROR。

WSARecvDisconnect函数的定义如下:

int WSARecvDisconnect(   SOCKET s,   LPWSABUF  lpInboundDisconnectData);
其中s为已建立连接的套接字,lpInboundDisconnectData为WSABUF结构的接收数据的缓冲区。其可以接收断开数据,只能接收由WSASendDisconnect函数发送的数据,不能接收普通数据。其接收完断开数据,就会取消接收远程通信方的数据,其作用和带参数的SD_RECEIVE的shutdown函数相同。

注意:在流协议上使用发送和和接收数据,无法保证接收和发送的数据量。

中断连接
      一旦用完了套接字连接,需要释放套接字连接,释放所有资源。可以有两个函数来实现:closesocket和shutdown。但是closesocket函数可能导致数据丢失,而shutdown就可以从容终止。

     为了保证通信方能够接收到应用程序发出的所有数据,好的应用程序,应该通知对方不要在发送数据。这个可以通过shutdown函数来实现,该函数定义如下:

int shutdown(   SOCKET s,   int      how);
s:为要关闭的套接字。how:为SD_SEND、SD_RECEIVE和SD_BOTH中一个。SD_RECEIVE表示不允许在调用接收函数,表示要重置连接。SD_SEND表示不允许在调用发送函数,对于TCP会将所有数据发送完且得到确认后,发送FIN包。SD_BOTH表示取消连接两端的收发操作。但并非所有的协议都支持从容关闭,因此需要注意。

closesocket函数用于关闭套接字。该函数会释放套接字描述符,并且会将所有队列中的数据。其定义如下:

int closesocket(SOCKET s); 

 2.无连接通信

         对于无连接的协议,操作过程相对比较简单。首先使用socket和WSASocket函数初始化套接字,然后使用bind函数将套接字绑定到准备接收数据的接口上,然后使用recvfrom和WSARecvFrom函数来接收数据,使用sendto和WSASendTo函数来发送数据。由于是无连接的,就没从容关闭和正常关闭的说法,如果套接字使用完了,可以调用closesocket函数来释放套接字分配的相关资源。

 recvfrom函数的定义如下:

int recvfrom(  SOCKET s,  char FAR *buf,  int len,  int flags,  struct sockaddr FAR *from,  int fromlen);
s、buf和len:和recv参数相同。flags:其可为MSG_OOB、MS_PEEK。from:其为一个SOCKADDR结构。fromlen:为from参数的长度。

recvfrom在Winsock2中的版本为WSARecvFrom,其定义如下:

int WSARecvFrom(       SOCKET s.    LPWSABUF lpBuffers,    DWORD dwBufferCount,    LPDWORD lpNumberOfByteRecvd,    DWORD dwFlags,    struct sockaddr FAR* lpfrom,    LPINT lpFromlen,    LPWSAOVERLAPPED lpOverlapped,    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);发送函数sendto,其定义如下:
int sendto(  SOCKET s,  char FAR *buf,  int len,  int flags,  struct sockaddr FAR *to,  int tolen
);

sendto在Winsock2中的版本为WSASendTo,其定义如下:

int WSASendTo(       SOCKET s.    LPWSABUF lpBuffers,    DWORD dwBufferCount,    LPDWORD lpNumberOfByteSent,    DWORD dwFlags,    struct sockaddr FAR* lpto,    LPINT lptolen,    LPWSAOVERLAPPED lpOverlapped,    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);在无连接套接字上建立连接:无连接套接字一旦建立,就可以使用SOCKADDR结构体调用conenct和WSAConnect函数来建立“单向连接”,这样就可以使用recv和WSARecv函数或send和WSASend函数来进行收发数据了。

3.一些重要的API函数

 1.getpeername

该函数用于获取通信方套接字的地址信息,该信息是关于已连接的那个套接字。其定义如下:

int getpeername(   SOCKET s,   sruct sockaddr FAR* name,   int FAR* namelen);

2.getsockname

该函数获取给定套接字的本地接口的地址信息。其定义如下:

int getpsockname(   SOCKET s,   sruct sockaddr FAR* name,   int FAR* namelen);

3.WSADuplicateSocket

WSADuplicateSocket函数用于建立WSAPROTOCOL_INFO结构,该结构体可传递到另一个进程。这样另一个进程就可以打开指向同一个套接字的句柄,这样这一个进程可以对该资源进行操作。其定义如下:

int WSADuplicateSocket(   SOCKET s,   DWORD dwProcessId,  LPWSAPROTOCOL_INFO lpProtocolInfo);

热点排行