VS2015中基于阻塞套接字的数据发送和接收(2-1)

《VS2015中基于TCP客户端的实现》《VS2015中基于TCP服务端的实现》中介绍了服务端将本端套接字设置为监听模式,客户端连接服务端,服务端接收客户端的连接。此时,客户端和服务端的套接字已经成功连接,接下来就是通过连接好的套接字进行数据发送和接收了。

1 数据的发送

通过send()函数或者WSASend()函数可以实现发送数据。WSASend()函数是Winsock2中的函数。Winsock1和Winsock2的相关知识请参考《Winsock网络编程头文件及库文件的设置》

1.1 send()函数

该函数的作用是通过已连接的套接字发送数据。

1.1.1 函数格式

send()函数的格式如下所示

int WSAAPI send(

 SOCKET s

, const char *buf

, int len

, int flags

);

其中,参数s是已连接的套接字;buf是保存了发送数据缓冲区的指针,该缓冲区中保存的数据都是以一个字节为单位的窄字符;len是缓冲区buf的大小;flags指定了发送数据时的方法,一般有三个取值,其中0表示常规的发送数据,第二个可能的取值是MSG_DONTROUTE,最后一个值是MSG_OOB,其中MSG_DONTROUTE表示数据不会被路由,MSG_OOB表示发送OOB数据。如果send()函数执行成功,则该函数返回的是实际发送数据的字节数,否则返回SOCKET_ERROR。需要注意的是,send()函数执行成功并不意味着对端能够成功收到数据,只是意味着发送端成功将数据发送出去。

相关链接1

OOB数据:OOB是out-of-band的缩写,其含义为带外数据。传输层协议使用带外数据来发送一些重要的数据。如果通信一方有重要的数据需要通知对方时,协议能够将这些数据快速地发送到对方。为了发送这些数据,协议一般不使用与普通数据相同的通道,而是使用另外的通道实现。

1.1.2 相关代码

在客户端中,通过以下代码实现向服务端发送数据的功能。

char *sendbuf = "Client: sending data test";

iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );

 if (iResult == SOCKET_ERROR)

{

wprintf(L"send failed with error: %d\n", WSAGetLastError()); closesocket(ConnectSocket);

WSACleanup();

 return 1;

}

printf("Bytes Sent: %d\n", iResult);

其中,sendbuf指向的缓冲区中是要发送的数据;ConnectSocket是连接服务端的套接字。如果发送数据失败,则通过WSAGetLastError()函数获取失败的信息,并且调用closesocket()函数关闭套接字,调用WSACleanup()函数释放资源。最后打印出发送数据的字节数iResult。

1.2 WSASend()函数

WSASend()函数与send()函数的作用相同,也是在已连接的套接字上发送数据。

1.2.1 函数格式

该函数的格式为

int WSAAPI WSASend(

SOCKET s

, LPWSABUF lpBuffers

, DWORD dwBufferCount

, LPDWORD lpNumberOfBytesSent

, DWORD dwFlags

, LPWSAOVERLAPPED lpOverlapped

, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine

);

其中,参数s是已经连接的套接字;lpBuffers是一个数组的指针,该数组中的元素是WSABUF结构的指针,每个WSABUF结构中包含了一个指向缓冲区的指针和该缓冲区的大小,这些缓冲区中包含了要发送的数据;dwBufferCount指定了lpBuffers数组中元素的个数;lpNumberOfBytesSend是实际发送数据的字节数,该变量是一个输出变量,与send()函数的返回值类似;dwFlags用来设置通过套接字发送数据时的方法,与send()函数的flags类似;lpOverlapped是一个WSAOVERLAPPED结构的指针,对于非重叠套接字,该参数可以忽略;lpCompletionRoutine是一个完成例程(completion routine)的指针,完成例程实际上是一个回调函数,当发送数据完成之后,该完成例程将会被调用,对于非重叠套接字,该参数可以忽略。如果调用WSASend()函数发送数据成功,则该函数返回值是0,否则返回值是SOCKET_ERROR。

相关链接2

WSABUF结构:WSABUF结构实际上就是一个缓冲区的描述,它为一些Winsock函数提供了创建或者操作数据缓冲区的机会。WSABUF结构的格式为:

typedef struct _WSABUF { 

ULONG len

; CHAR *buf;

} WSABUF, *LPWSABUF;

其中,len是缓冲区的大小,buf是缓冲区的指针。

1.2.2 相关代码

在客户端中,通过以下代码实现向服务端发送数据的功能。

#define DATA_BUFSIZE 4096

WSABUF DataBuf;

DWORD SendBytes;

DataBuf.len = DATA_BUFSIZE;

DataBuf.buf = “Client: sending data test”;

int rc = WSASend(

ConnectSocket

, &DataBuf

, 1

, &SendBytes

, 0

, NULL

, NULL);

 if (rc == SOCKET_ERROR)

 {

 printf("WSASend failed with error: %d\n", err);

 }

其中,WSASend()函数的参数ConnectSocket是连接服务端的套接字;DataBuf是WSABUF结构的对象,包含了要发送的内容;SendBytes中保存了实际向服务端发送的字节数。

1.2.3 WSASend()函数与send()函数的区别

从以上介绍可知,WSASend()函数与send()函数的作用都是通过已连结的套接字向对端发送数据。当发送的数据比较少的时候,两个函数的功能差不多。当发送的数据比较多时,需要多次调用send()函数才会实现,作为Winsock API函数的send(),实际上调用了相应的内核函数。多次调用send()函数会导致多次调用内核函数,这样会消耗大量时间。虽然WSASend()函数实际上也是调用了相应的内核函数,但是该函数可以与多个WSABUF相关连,WSABUF实际上就是一个保存数据的内容,当发送的数据较多时,系统先将要发送的数据保存到与WSASend()函数关连的多个WSABUF对象中,之后再调用WSASend()函数一起将数据进行发送,这样就减少了调用内核函数的次数,节约了时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值