关于Windows Socket完成端口的问题

kilou 2006-09-26 09:57:01
最近公司需要编制一个测试WINDOWS Socket 2.x API处理速度的服务器小程序,本人将《WINDOWS网络编程技术》一书中的第八章的服务器例子Chapter08\IOcmplt直接在BCB6.0中编译后,当客户端连接数小于58个时,服务器端不会出错,当大于58时提示两个错:
WSARecv() failed with error 10053
WSARecv() failed with error 10053
Tue Sep 26 00:50:06 2006

当客户端连接大于200时提示:
WSARecv() failed with error 10053
WSARecv() failed with error 10053
Tue Sep 26 00:55:06 2006
GetQueuedCompletionStatus failed with error 995

希望高手指点迷津!!

源码如下:
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <time.h>

#define PORT 5150
#define DATA_BUFSIZE 8192

#pragma comment(lib, "ws2_32.lib")
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;


typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;


DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);

char str[80];
time_t t;

void main(void)
{
SOCKADDR_IN InternetAddr;
SOCKET Listen;
SOCKET Accept;
HANDLE CompletionPort;
SYSTEM_INFO SystemInfo;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsaData;
DWORD Ret;



printf("FD_SETSIZE is %d \n", FD_SETSIZE);


if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
printf("WSAStartup failed with error %d\n", Ret);
return;
}

// Setup an I/O completion port.

if ((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
{
printf( "CreateIoCompletionPort failed with error: %d\n", GetLastError());
return;
}

// Determine how many processors are on the system.

GetSystemInfo(&SystemInfo);

// Create worker threads based on the number of processors available on the
// system. Create two worker threads for each processor.

for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++)
{
HANDLE ThreadHandle;

// Create a server worker thread and pass the completion port to the thread.

if ((ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,
0, &ThreadID)) == NULL)
{
printf("CreateThread() failed with error %d\n", GetLastError());
return;
}

// Close the thread handle
CloseHandle(ThreadHandle);
}

// Create a listening socket

if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return;
}

printf("WSASocket() 创建成功... \n");
time(&t);
strcpy(str, asctime(gmtime(&t)));
printf("%s\n", str);

InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);

if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return;
}

printf("bind() 成功... \n");

// Prepare socket for listening

if (listen(Listen, 500) == SOCKET_ERROR)
{
printf("listen() failed with error %d\n", WSAGetLastError());
return;
}

printf("Agent服务器侦听中 ... \n");

// Accept connections and assign to the completion port.

while(TRUE)
{
if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, 0)) == SOCKET_ERROR)
{
printf("WSAAccept() failed with error %d\n", WSAGetLastError());
return;
}

printf("有客户端连接到Agent服务器 ... \n");

// Create a socket information structure to associate with the socket
if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,
sizeof(PER_HANDLE_DATA))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return;
}

// Associate the accepted socket with the original completion port.

printf("Socket number %d connected\n", Accept);
PerHandleData->Socket = Accept;

if (CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData,
0) == NULL)
{
printf("CreateIoCompletionPort failed with error %d\n", GetLastError());
return;
}

// Create per I/O socket information structure to associate with the
// WSARecv call below.

if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA))) == NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return;
}

ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->BytesSEND = 0;
PerIoData->BytesRECV = 0;
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;

Flags = 0;
if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return;
}
}
}
}
...全文
862 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
ttii 2006-10-03
  • 打赏
  • 举报
回复

一个getsockopt的Example


optval = ...打印出来的就是socket收数据buffer的大小

#include
#include
#include
int main()
{
int s = 0;
int optval;

socklen_t optlen = sizeof(int);
if((s = socket(AF_INET,SOCK_STREAM,0))<0) perror("socket");

getsockopt(s, SOL_SOCKET, SO_RCVBUF, &optval, &optlen);
printf("optlen = %d\n, optval = %d", optlen, optval);
close(s);
return 0;
}

ttii 2006-10-03
  • 打赏
  • 举报
回复
相关函数:setsockopt
表头文件:#include <sys/types.h>
#include <sys/socket.h>
函数定义:int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
函数说明:getsockopt()会将参数s所指定的socket状态返回。
参数optname代表欲取得何种选项状态
参数optval则指向欲保存结果的内存地址,
参数optlen则为该空间的大小
参数level、optname请参setsockopt()
错误代码:EBADF 参数s并非合法的socket处理代码
ENOTSOCK 参数s为一文件描述词,非socket
ENOPROTOOPT 参数optname指定的选项不正确
EFAULT 参数optval指针指向无法存取的内存空间
范例:
include <sys/types.h>
inlcude <sys/socket.h>

main()
{
int s, optval, optlen=sizeof(int);
if((s=socket(AF_INET, SOCK_STREAM, 0)) <0)
perror("socket");
getsockopt(s, SOL_SOCKET, SO_TYPE, &optval, &optlen);
printf("optval = %d\n", optval);
close(s);
}
ttii 2006-10-03
  • 打赏
  • 举报
回复
这个模型是对的,我也用的这种模型,这个错误是由于你server存在同一个连接导致的,从10053字面意思上分析,就是这个意思,那么从这个角度来讲,就是说由于你连接了58个小时,中间很有可能有什么异常中断了,而server没有进行这个中断后的socket回收,而客户端又进行了连接,另外简单看了一下你的模型,少了一个这种处理,因此判断这个问题的原因应该就是没有进行连接处理导致的,你可以在主线程,或者是在另外建立一个检查线程来做这个处理,给你一段伪代码,你修改以后再进行一下测试,希望对你有所帮助
for(;;)
{
if( lp_io状态state != 连接并读写 ) //此时就需要检测是否需要踢掉
{
getsockopt(socket, SOL_SOCKET, SO_CONNECT_TIME, (char*)&op, &op_len );

if( op != 0xffffffff && op > 20 )
{
msg("有一个连接,但没有接收到数据,已经被踢出去了");
close(sokcet);

}
else
{
//可以提示或者什么也不做;
}
}
}
do2008 2006-10-03
  • 打赏
  • 举报
回复
学习,mark一下,帮顶
我不懂电脑 2006-09-26
  • 打赏
  • 举报
回复
一個已建立的連接被你的主機上的軟體終止,可能是因為一次資料傳輸超時或是傳輸協定錯誤。
可以把超时设长一些。
kilou 2006-09-26
  • 打赏
  • 举报
回复

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;
char chChange[26] = "---Agent returns data----";
chChange[24] = '\n';

while(TRUE)
{

if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
{
printf("GetQueuedCompletionStatus failed with error %d\n", GetLastError());
return 0;
}


// First check to see if an error has occured on the socket and if so
// then close the socket and cleanup the SOCKET_INFORMATION structure
// associated with the socket.

if (BytesTransferred == 0)
{
printf("Closing socket %d\n", PerHandleData->Socket);

if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
return 0;
}

GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}

// Check to see if the BytesRECV field equals zero. If this is so, then
// this means a WSARecv call just completed so update the BytesRECV field
// with the BytesTransferred value from the completed WSARecv() call.

if (PerIoData->BytesRECV == 0)
{
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = 0;
}
else
{
PerIoData->BytesSEND += BytesTransferred;
}

if (PerIoData->BytesRECV > PerIoData->BytesSEND)
{

// Post another WSASend() request.
// Since WSASend() is not gauranteed to send all of the bytes requested,
// continue posting WSASend() calls until all received bytes are sent.

ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

time(&t);
strcpy(str, asctime(gmtime(&t)));
printf("%s\n", str);

PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND ;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND;
// strcpy(PerIoData->DataBuf.buf+PerIoData->DataBuf.len, chChange);
// PerIoData->DataBuf.len = PerIoData->DataBuf.len + 24;

// PerIoData->DataBuf.buf = PerIoData->DataBuf.buf + PerIoData->DataBuf.buf;
// PerIoData->DataBuf.len = PerIoData->DataBuf.len + PerIoData->DataBuf.len;

// Sleep(0);

if (WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
return 0;
}
}
}
else
{
PerIoData->BytesRECV = 0;

// Now that there are no more bytes to send post another WSARecv() request.

Flags = 0;
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));

PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;

if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return 0;
}
}
}
}
}
//---------------------------------------------------------------------------




netliuming 2006-09-26
  • 打赏
  • 举报
回复
"一個已建立的連接被你的主機上的軟體終止,可能是因為一次資料傳輸超時或是傳輸協定錯誤",如果是这个原因的话,个人感觉设置超时长一些估计也不能解决问题,因为很多原因会导致这个结果,比如有些路由器就会把一些长时间没有传输的连接关掉。

1,222

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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