windows上异步socket怎样正确的发送

zhousitiaoda 2016-08-16 04:24:27
send,我的理解是把数据发送到缓冲区,到了缓冲区后由TCP协议来保证数据完整的发送过去。
标准的做法是否必须得像下面这样

int SendRequest(int socket_fd,const char*send_buffer,long size)
{
int ret = -1;
int Total = 0;
int lenSend = 0;

struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 500;
fd_set wset;
while(1)
{
FD_ZERO(&wset);
FD_SET(socket_fd, &wset);
if(select(socket_fd + 1, NULL, &wset, NULL, &tv) > 0)//3.5秒之内可以send,即socket可以写入
{
lenSend = send(socket_fd,send_buffer + Total,size -Total,0);
if(lenSend == -1)
{
ret = SEND_FAIL;
break;
}
Total += lenSend;
if(Total == size)
{
ret = OK;
break;
}
}
else //3.5秒之内socket还是不可以写入,认为发送失败
{
ret = SEND_FAIL;
break;
}
}
return ret;
}
...全文
1514 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
wf_it_life 2016-09-16
  • 打赏
  • 举报
回复
应该可以
Eleven 2016-09-16
  • 打赏
  • 举报
回复
非阻塞socket IO模式,select,/WSAAsyncSelect/WSAEventSelect/Overlap IO/IOCP
dong364 2016-09-16
  • 打赏
  • 举报
回复
同步的send做法,就是把应用层的发送缓冲区拷贝到内核层的发送缓冲区后就返回了,如果内核层的发送缓冲区满,那么就等到内核层的发送缓冲区释放足够拷贝的空间后进行拷贝,然后返回; 异步的send做法,其实就是多了一个发送缓冲队列,所以每次调用可以立即返回。 楼主举得例子是超时,不太恰当,发送超时跟发送底层实现原理不是一码事。
oyljerry 2016-08-18
  • 打赏
  • 举报
回复
Windows上异步IO就是用IOCP了,用它的API来发送数据
sevancheng 2016-08-17
  • 打赏
  • 举报
回复
引用 楼主 zhousitiaoda 的回复:
send,我的理解是把数据发送到缓冲区,到了缓冲区后由TCP协议来保证数据完整的发送过去。 标准的做法是否必须得像下面这样

int SendRequest(int  socket_fd,const char*send_buffer,long size)    
{    
    int ret = -1;    
    int Total = 0;    
    int lenSend = 0;    
      
    struct timeval tv;    
    tv.tv_sec = 3;    
    tv.tv_usec = 500;    
    fd_set wset;    
    while(1)    
    {    
        FD_ZERO(&wset);    
        FD_SET(socket_fd, &wset);    
        if(select(socket_fd + 1, NULL, &wset, NULL, &tv) > 0)//3.5秒之内可以send,即socket可以写入    
        {    
            lenSend = send(socket_fd,send_buffer + Total,size -Total,0);    
            if(lenSend == -1)    
            {    
                ret = SEND_FAIL;    
                break;    
            }    
            Total += lenSend;    
            if(Total == size)    
            {    
                ret = OK;    
                break;    
            }    
        }    
        else  //3.5秒之内socket还是不可以写入,认为发送失败  
        {    
            ret = SEND_FAIL;    
            break;    
        }    
    }    
    return ret;    
}   
我觉得这样挺好的
zgl7903 2016-08-17
  • 打赏
  • 举报
回复
MSDN 的例子

/******************************************************************************\
* ioctl.c - TCP server
*
*       This is a part of the Microsoft Source Code Samples.
*       Copyright 1996-1997 Microsoft Corporation.
*       All rights reserved.
*       This source code is only intended as a supplement to
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the
*       Microsoft samples programs.
\******************************************************************************/



#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_PORT 5001

int ReadAndEcho(SOCKET , char *,int ) ;
int WriteMessage(SOCKET , char *,int ) ;

void Usage(char *progname) {
	fprintf(stderr,"Usage\n%s -e [endpoint] -i [interface]\n",
		progname);
	fprintf(stderr,"Where:\n");
	fprintf(stderr,"\tendpoint is the port to listen on\n");
	fprintf(stderr,"\tinterface is the ipaddr (in dotted decimal notation)");
	fprintf(stderr," to bind to\n");
	fprintf(stderr,"Defaults are 5001 and INADDR_ANY\n");
	WSACleanup();
	exit(1);
}
int main(int argc, char **argv) {

	char Buffer[128];
	char *interface= NULL;
	unsigned short port=DEFAULT_PORT;
	int fromlen;
	int i, ioctl_opt =1;
	struct sockaddr_in local, from;
	WSADATA wsaData;
	SOCKET listen_socket, msgsock;
	fd_set readfds, writefds, exceptfds;

	/* Parse arguments */
	if (argc >1) {
		for(i=1;i <argc;i++) {
			if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
				switch(tolower(argv[i][1])) {
					case 'i':
						interface = argv[++i];
						break;
					case 'e':
						port = atoi(argv[++i]);
						break;
					default:
						Usage(argv[0]);
						break;
				}
			}
			else
				Usage(argv[0]);
		}
	}
	
	if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
		fprintf(stderr,"WSAStartup failed with error %d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}
	
	if (port == 0){
		Usage(argv[0]);
	}

	//
	// The fd sets should be zeroed out before using them to prevent errors.
	FD_ZERO(&readfds);
	FD_ZERO(&writefds);
	FD_ZERO(&exceptfds);
	memset(Buffer,0,sizeof(Buffer));

	local.sin_family = AF_INET;

	//
	// bind to specific interface if desired.

	local.sin_addr.s_addr = (!interface)?INADDR_ANY:inet_addr(interface); 

	/* 
	 * Port MUST be in Network Byte Order
	 */
	local.sin_port = htons(port);

	listen_socket = socket(AF_INET, SOCK_STREAM,0); // TCP socket
	if (listen_socket == INVALID_SOCKET){
		fprintf(stderr,"socket() failed with error %d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}
	//
	// bind() associates a local address and port combination with the
	// socket just created. 

	if (bind(listen_socket,(struct sockaddr*)&local,sizeof(local) ) 
		== SOCKET_ERROR) {
		fprintf(stderr,"bind() failed with error %d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}

	//
	// start listening on the socket for incoming connections
	//
	if (listen(listen_socket,5) == SOCKET_ERROR) {
		fprintf(stderr,"listen() failed with error %d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}
	printf("%s: Listening on port %d\n",argv[0],port);

	//
	// Set the socket to non-blocking mode.
	//
	if (ioctlsocket(listen_socket,FIONBIO,&ioctl_opt) == SOCKET_ERROR) {
		fprintf(stderr,"ioctlsocket failed %d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}
	//
	// The structure of the loop below is very simple. We only accept one
	// connection at a time. As soon as another client connects, we
	// disconnect the first one, and start talking to the new client.
	// All this server does is to echo the data received on the socket
	// back to the client.
	//
	// This is not a very realistic server, but it does serve to show that
	// select() does not scale very well on win32. If we were dealing
	// with more than one client, we would have to have a list of sockets
	// that are in each fdset to be able to check them when select()
	// returns.
	//
	while(1) {

		//
		// A socket in the listen() state becomes ready to read when a
		// client connects to it. An accept() will complete without
		// blocking.
		// Since select sets the sockets that are ready to be read from or
		// written to, we have to include listen_socket in the fdset each time
		// through the loop.
		//

		FD_SET(listen_socket,&readfds);

		i = select(0,&readfds,&writefds,&exceptfds,NULL);
		if (i == SOCKET_ERROR) {
			fprintf(stderr,"select failed %d\n",WSAGetLastError());
		}
		if (i==0){
			fprintf(stderr,"Select returned no fds ready\n");
		}

		if (FD_ISSET(listen_socket, &readfds)){
			//
			// close the previous client socket. 
			// We must also clear it from the fdset to prevent select()
			// from failing.
			//
			closesocket(msgsock);
			FD_CLR(msgsock,&readfds);
			FD_CLR(msgsock,&writefds);
			fromlen = sizeof(from);
			msgsock= accept(listen_socket,(struct sockaddr*)&from,&fromlen);
			if (msgsock == INVALID_SOCKET) {
				fprintf(stderr,"accept failed %d\n",WSAGetLastError());
				WSACleanup();
				return -1;
			}
			FD_SET(msgsock,&writefds);
			FD_SET(msgsock,&readfds);
			continue;
		}
		if (FD_ISSET(msgsock,&readfds) ) {
			//
			// socket is ready to read, i.e., there is data on the socket.
			//
			if (ReadAndEcho(msgsock,Buffer,sizeof(Buffer))<0) {
				fprintf(stderr,"terminating connection\n");
				FD_CLR(msgsock,&readfds);
				FD_CLR(msgsock,&writefds);
				closesocket(msgsock);
				continue;
			}
		}
		if (FD_ISSET(msgsock,&writefds) ){
			if (WriteMessage(msgsock,Buffer,sizeof(Buffer)) <=0) {
				fprintf(stderr,"terminating connection\n");
				FD_CLR(msgsock,&readfds);
				FD_CLR(msgsock,&writefds);
				closesocket(msgsock);
				continue;
			}
		}
		FD_SET(msgsock,&writefds);
		FD_SET(msgsock,&readfds);
	}
}
int ReadAndEcho(SOCKET insock, char *Buffer,int size) {
	int rc;

	rc = recv(insock,Buffer,size,0);

	if (rc == SOCKET_ERROR) {
		fprintf(stderr,"recv() failed with error %d\n",WSAGetLastError());	
		return -1;
	}
	if (rc ==0) {
		fprintf(stderr,"Connection closed by client\n");
		return 0;
	}
	printf("Received [%s] from client\n",Buffer);
	return rc;
}
int WriteMessage(SOCKET outsock, char *Buffer,int size) {
	int rc;
	int lasterr;

	printf("Sending [%s] to client\n",Buffer);
	rc = send(outsock,Buffer,size, 0);

	if (rc == SOCKET_ERROR) {
	  lasterr = WSAGetLastError();
	  if (lasterr == WSAEWOULDBLOCK)
		return 0;
	  else {
		fprintf(stderr,"send() failed with error %d\n",lasterr);	
		return -1;
	  }
	}
	if (rc ==0) {
		fprintf(stderr,"Connection closed by client\n");
	}
	return rc;
}

转角天边 2016-08-16
  • 打赏
  • 举报
回复
https://git.oschina.net/1050676515/Artemis.git 里面有IOCP的用法,用的WSASend和WSARecv,持续更新中
www_adintr_com 2016-08-16
  • 打赏
  • 举报
回复
通常情况下, 只要 send 没有返回错误就不用管它了. 如果系统缓冲中的数据最终无法发送给对方并受到确认, 会在之后使用 socket 的时候得到错误消息. 然后一般会重新连接, 状态会重新初始化, 之前没发送出去的那一点数据也无所谓了. 如果一定要确认对方收到了你发送的数据才能进行下一步操作, 可以把 socket 上的缓冲区设置为空, 这样 send 函数就会等到对方收到数据的确认包回来后才会返回.
赵4老师 2016-08-16
  • 打赏
  • 举报
回复
zhousitiaoda 2016-08-16
  • 打赏
  • 举报
回复
或者说求一个异步socket标准的规范的send\recv操作

18,363

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧