当前位置: 首页 > >

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

发布时间:

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
);



友情链接: 简历 面试求职范文 职业规划 自我管理 社交礼仪 76242百科