Archive for the ‘网络编程’ Category.

setsockopt设置组播返回10042(WSAENOPROTOOPT)错误

在编写组播程序时,需要加入组播组,调用setsockopt设置IP_ADD_MEMBERSHIP,代码如下:

/* join a multicast group */
if (multiaddr)
{ 
	struct ip_mreq mreq;
	mreq.imr_multiaddr.s_addr = inet_addr(multiaddr);
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) < 0)
	{
		printf("setsockopt error, code;"<<WSAGetLastError());
	}
}

Continue reading ‘setsockopt设置组播返回10042(WSAENOPROTOOPT)错误’ »

调用WinINet的HttpSendRequest返回12002超时

在使得WinINet进行文件下载时,发现前几次都能够正常下载,但在某一次操作以后,调用HttpSendRequest一直失败,返回错误号是12002,查询MSDN,对这个错误的描述是The request has timed out.

经过排查发现,工作到某一次时,没有关闭request句柄,导致后续调用HttpSendRequest一直失败,按照顺序关闭request句柄问题解决。

if (hReq)
{
	InternetCloseHandle(hReq);
}
if (hConnect)
{
	InternetCloseHandle(hConnect);
}
if (hOpen)
{
	InternetCloseHandle(hOpen);
}

SOCKET检测TCP是否断线的三种方法

目前主要有三种方法来实现用户掉线检测:SO_KEEPALIVE ,SIO_KEEPALIVE_VALS 和Heart-Beat线程。
下面我就上面的三种方法来做一下介绍。

一、SO_KEEPALIVE机制

这是socket库提供的功能,设置接口是setsockopt API:


BOOL bSet=TRUE;
setsockopt(hSocket,SOL_SOCKET,SO_KEEPALIVE,(const char*)&bSet,sizeof(BOOL));

根据MSDN的文档,如果为socket设置了KEEPALIVE选项,TCP/IP栈在检测到对方掉线后,任何在该socket上进行的调用(发送/接受调用)就会立刻返回,错误号是WSAENETRESET,同时,此后的任何在该socket句柄的调用会立刻失败,并返回WSAENOTCONN错误。

Continue reading ‘SOCKET检测TCP是否断线的三种方法’ »

用TCP协议传送文件可防止粘包

有时候TCP传输会出现粘包情况,网上流行几种说法,一种是在发送的时候加个sleep,让发送不至于过快引起粘包,但这种会影响发送效率,这个sleep并且微秒级的,也就是说sleep(1)与sleep(40)差别不大,废话不多说,下面这段代码经测试可预防粘包。


//以下是测试结构
typedef struct tagRequest
{
    UINT nMagic;
    UINT ncbSize;
    //
    // 这中间可以写点别的
    //
    //
    //数据长度
    UINT nContentLength;

}REQUEST,*PREQUEST,*LPREQUEST;

#define     REQUEST_MAGIC        0x12345678
#define  REQUEST_SIZE            (sizeof(tagRequest))

typedef struct tagResponse
{
    UINT nMagic;
    UINT ncbSize;
    //
    // 这中间可以写点别的
    //
    //
    //数据长度
    UINT nContentLength;
}RESPONSE,*PRESPONSE,*LPRESPONSE;

Continue reading ‘用TCP协议传送文件可防止粘包’ »

UDP的recvfrom产生10054的错误

这个是Windows的问题。

当UDP Socket在某次发送后收到一个不可到达的ICMP包时,这个错误将在下一个接收中返回。所以上面的套接字在下一次的接收中返回了SOCKET_ERROR,错误是10054

解决方法:

简单的忽略这个就可以了,对后续的调用没有影响。

//防止sendto不能到达后recvfrom返回-1并且获得10054错误.
/*
SYMPTOMS:
In Windows 2000, a User Datagram Protocol (UDP) program may not work and may generate a
WSAECONNRESET response.
CAUSE:
If sending a datagram using the sendto function results in an "ICMP port unreachable"
response and the select function is set for readfds, the program returns 1 and the subsequent
call to the recvfrom function does not work with a WSAECONNRESET (10054) error response.
In Microsoft Windows NT 4.0, this situation causes the select function to block or time out.
//用来防止q263823(见MSDN)(UDP中sendto发送的消息到不了指定的IP&PORT后使用recvfrom的话会返回-1,报错10054)
*/
DWORD ? dwBytesReturned ? = ? 0;
BOOL ? ? bNewBehavior ? = ? FALSE;
DWORD ? status;
status = WSAIoctl(mainSocket, SIO_UDP_CONNRESET,&bNewBehavior,sizeof(bNewBehavior),NULL,0,&dwBytesReturned,NULL,NULL);