一个重叠I/O套接字的问题

pf_ma 2001-09-26 09:57:41
加精
我现在正在试 重叠I/O套接字的完成例程
但我的实验程序好象有问题,那位大虾能帮我看看


程序运行到 WSARecv,提示 重叠I/O初始化成功,
但客户端Send之后,并没有调用 完成例程,请问为什么?


附上源代码


//**********************************************

#include <winsock2.h>
#include <stdio.h>


typedef struct
{
WSAOVERLAPPED wol;
SOCKET s;
CHAR buf[100];
WSABUF wbuf;
DWORD dwc;
}OLX;


VOID CALLBACK cr(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);


DWORD rlen;
DWORD flag = 0;


VOID main()
{
WSADATA wd;
WSAStartup(0x0202, &wd);


CHAR hostname[512];
gethostname(hostname, 512);
HOSTENT * pht = gethostbyname(hostname);
printf("Server IP:%s\n", inet_ntoa(*(IN_ADDR *)(pht->h_addr_list[0])));


SOCKET ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ls != INVALID_SOCKET) printf("socket ok...\n");

SOCKADDR_IN saddr;
saddr.sin_family = AF_INET;
saddr.sin_addr.S_un.S_addr = 0;
saddr.sin_port = htons(5050);


INT irv = bind(ls, (SOCKADDR *)&saddr, sizeof(SOCKADDR));
if (irv != SOCKET_ERROR) printf("bind ok...\n");


irv = listen(ls, 5);
if (irv != SOCKET_ERROR) printf("listen ok...\n");


DWORD dwrv = 1;
irv = ioctlsocket(ls, FIONBIO, &dwrv);
if (irv != SOCKET_ERROR) printf("ioctlsocket ok...\n");


printf("\n");
while(1)
{
SOCKET s = accept(ls, NULL, NULL);
if (s != INVALID_SOCKET)
{
printf("\naccept ok...\n");


OLX * polx = new OLX;
memset(polx, 0, sizeof(OLX));


polx->s = s;
polx->wbuf.buf = polx->buf;
polx->wbuf.len = 100;


INT irv = WSARecv(s, &(polx->wbuf), 1, &rlen, &flag, &(polx->wol), cr);
if (irv == 0) printf("\nWSARecv ok...\n");
if (WSAGetLastError() == WSA_IO_PENDING) printf("\nWSARecv WSA_IO_PENDING...\n");
}
Sleep(10);
}


closesocket(ls);
WSACleanup();
}


VOID CALLBACK cr(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
printf("call back ...");

OLX * polx = (OLX *)lpOverlapped;


INT irv = WSARecv(polx->s, &(polx->wbuf), 1, &rlen, &flag, &(polx->wol), crzzzz);
printf(".");
}


//**********************************************



...全文
556 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
alwaysakid 2001-09-28
  • 打赏
  • 举报
回复
在这里使用sleepEx或者waitforsingleobject都是完全错误的,因为既然要等待,使用apc就没有了意义,使用异步方式也没有任何意义。
我上面的帖子用sleepex仅仅是为了说明为了让apc执行,必须出于alertable状态
pf_ma 2001-09-28
  • 打赏
  • 举报
回复
谢谢大家,特别是alwaysakid(老A)非常感谢!@^0^@
pf_ma 2001-09-28
  • 打赏
  • 举报
回复
还有,我试下来,APC运行在调用线程上,在APC上的Sleep();将导致调用线程睡眠
pf_ma 2001-09-28
  • 打赏
  • 举报
回复
To alwaysakid(老A)
除了sleepex,waitforsingleobject之类的,还有其他让apc执行的方法吗?
pf_ma 2001-09-27
  • 打赏
  • 举报
回复
To alwaysakid(老A):


SleepEx(0,TRUE); 好象不行
SleepEx(1000,TRUE); 可以


SleepEx(0,TRUE); 是为了激活"APC"吗?


Windows的完成例程的机制究竟是什么?
完成例程究竟是由系统自身调用的,运行在系统自身线程之上,
还是线程假借系统之手而调用的,运行在调用线程之上,
或者是其他的什么机制?
tpProgramer 2001-09-27
  • 打赏
  • 举报
回复
DWORD SleepEx(DWORD dwMillisecondes,BOOL bAlertable)
bAlertable规定了一个完成例程的执行方式,如果bAlertable设为FALSE,而且进行了一次I/O完成回调,那么I/O完成函数不会执行,而且函数不会返回,除非超过由dwMilliseconds规定的时间,若设为TRUE,那么完成例程会得到执行,同时SleepEx函数返回WAIT_IO_COMPLETION.


这里的SleepEx函数相当于一个WaitForSingleObject函数(或者WaitForMultipleObjects),等待一个事件的发生.
alwaysakid 2001-09-27
  • 打赏
  • 举报
回复
1.其实0还是1000没有区别,因为网络情况的不确定性,没有办法确定sleep多长时间才“足够“,真正起作用的还是TRUE.

2.在这里使用SLEEPEX仅仅是为了简单,其实是不正确的做法。

3.异步IO(包括完成端口)运行在系统的IO线程池中的某一个线程上,完成后系统简单的将完成例程放入线程的APC队列当中,(但不执行),当线程首次被唤醒时所有已经在APC队列中的APC都会执行。所以线程必须处于可唤醒的状态,APC才能执行。

4。这样做的好处是显而易见的,假设系统直接在IO线程上调用你的APC,一方面,系统不知道你的线程的运行状态,另一方面你的线程不知道IO线程是哪一个,两者之间根本没有办法同步,如果两个线程都访问了某个变量,就非常混乱了。
所以WINDOWS认为最好的方案是,第一,绝对不在调用线程之外的其他线程上执行APC(APC是特定于线程的,每个线程都有自己的APC队列),第二,必须等到调用线程明确表示可以执行APC(可唤醒)的时候才执行APC.

alwaysakid 2001-09-27
  • 打赏
  • 举报
回复
....WSARecv(...)
SleepEx(0,TRUE);
pf_ma 2001-09-27
  • 打赏
  • 举报
回复
up
mimihuhu 2001-09-27
  • 打赏
  • 举报
回复
push
pf_ma 2001-09-27
  • 打赏
  • 举报
回复
up
pf_ma 2001-09-27
  • 打赏
  • 举报
回复
up
jyc5131 2001-09-26
  • 打赏
  • 举报
回复
关注
pf_ma 2001-09-26
  • 打赏
  • 举报
回复
up
pf_ma 2001-09-26
  • 打赏
  • 举报
回复
//*************************************

VOID CALLBACK cr(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
printf("call back ...");

OLX * polx = (OLX *)lpOverlapped;


INT irv = WSARecv(polx->s, &(polx->wbuf), 1, &rlen, &flag, &(polx->wol), crzzzz);
printf(".");
}

//*************************************

中"crzzzz"应是"cr",这里是笔误


pf_ma 2001-09-26
  • 打赏
  • 举报
回复
现在附上客户端程序源代码

//*************************************

#include <winsock2.h>
#include <stdio.h>


VOID main()
{
WSADATA wd;
WSAStartup(0x0202, &wd);


CHAR ServerIP[100];
printf("Server IP:");
scanf("%s", ServerIP);
printf("\n\n");


SOCKADDR_IN caddr;
SOCKADDR_IN saddr;


caddr.sin_family = AF_INET;
caddr.sin_addr.S_un.S_addr = 0;
caddr.sin_port = 0;
saddr.sin_family = AF_INET;
saddr.sin_addr.S_un.S_addr = inet_addr(ServerIP);
saddr.sin_port = htons(5050);


SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s != INVALID_SOCKET) printf("socket ok...\n");


INT irv = bind(s, (SOCKADDR *)&caddr, sizeof(SOCKADDR));
if (irv != SOCKET_ERROR) printf("bind ok...\n");


irv = connect(s, (SOCKADDR *)&saddr, sizeof(SOCKADDR));
if (irv != SOCKET_ERROR) printf("connect ok...\n");


while(irv != SOCKET_ERROR)
{
Sleep(1000);


CHAR buf[1000] = "Test OverLapped I/O Mode.";


irv = send(s, buf, 1000, 0);


printf(".");
}


closesocket(s);
WSACleanup();
}


//*************************************
pf_ma 2001-09-26
  • 打赏
  • 举报
回复
up
mimihuhu 2001-09-26
  • 打赏
  • 举报
回复
push~~
pf_ma 2001-09-26
  • 打赏
  • 举报
回复
up
Jneu 2001-09-26
  • 打赏
  • 举报
回复
up
加载更多回复(1)

4,357

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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