WSAEventSelect模型“Ctrl+C”是否能关闭掉服务端?

qingdujun
博客专家认证
2019-03-31 04:24:36
大家好!我遇到一个很奇怪的问题。我尝试着使用`WSAEventSelect `写了一个回射服务端。再写了一个客户端程序,去连接它。

一切都正常。

然后奇怪的是,当我对服务端exe使用“Ctrl+C”时,客户端并没有任何反应?此时,我在客户端上发任何字符串,还是能被回射过来。

我索性直接把服务端exe退出了,这时候我想着客户端应该也挂掉了吧?

奇怪的是,客户端的数据还能被回射。

---------------

我也几乎能确定服务端确实是退出了,因为我新启一个客户端,无法连接到服务端。

但是,原来连上去的客户端,并没有因为服务端的关闭而受影响?很奇怪。

源代码1:服务端程序

#include <WinSock2.h>
#include <stdio.h>

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

#define SERV_PORT 9527
#define MAXLINE 128
#define LISTENQ 5
#define MAXBUFSIZE 1024

void exit_msg(const char* msg) {
perror(msg);
exit(0);
}

int main(int argc, char* argv[]) {
int listenfd, connfd, cevents, idx, clilen, i, n;
struct sockaddr_in cliaddr, servaddr;
char buf[MAXBUFSIZE];
WSAEVENT event, wsaevents[WSA_MAXIMUM_WAIT_EVENTS];//<WinSock2.h> #define WSA_MAXIMUM_WAIT_EVENTS 64
WSANETWORKEVENTS net_events;
SOCKET sockets[WSA_MAXIMUM_WAIT_EVENTS];
WSADATA wsa;

WSAStartup(MAKEWORD(2, 2), &wsa);

listenfd = socket(AF_INET, SOCK_STREAM, 0);

memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);

if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
exit_msg("bind error");

listen(listenfd, LISTENQ);
//1、创建并设置WSACreateEvent
event = WSACreateEvent();
WSAEventSelect(listenfd, event, FD_ACCEPT | FD_CLOSE);
cevents = 0;
wsaevents[cevents] = event;
sockets[cevents] = listenfd;
++cevents;

for (; ; ) {
//2、WSAWaitForMultipleEvents等待事件被触发
if ((idx = WSAWaitForMultipleEvents(cevents, wsaevents, FALSE, WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED)
exit_msg("WSA_WAIT_FAILED");

if (idx == WSA_WAIT_TIMEOUT)
continue;

idx -= WSA_WAIT_EVENT_0;
//3、WSAEnumNetworkEvents获取具体发生的事件类型
WSAEnumNetworkEvents(sockets[idx], wsaevents[idx], &net_events);
WSAResetEvent(wsaevents[idx]);//4、设置事件为无信号状态
if (net_events.lNetworkEvents & FD_ACCEPT) {
puts("FD_ACCEPT");
if (net_events.iErrorCode[FD_ACCEPT_BIT] == 0) {
if (cevents >= WSA_MAXIMUM_WAIT_EVENTS)
exit_msg("too many clients");
clilen = sizeof(cliaddr);
connfd = accept(sockets[idx], (struct sockaddr*)&cliaddr, &clilen);
event = WSACreateEvent();
WSAEventSelect(connfd, event, FD_READ | FD_WRITE | FD_CLOSE);
wsaevents[cevents] = event;
sockets[cevents] = connfd;
++cevents;
}
}
if (net_events.lNetworkEvents & FD_READ) {
puts("FD_READ");
if (net_events.iErrorCode[FD_READ_BIT] == 0) {
if ((n = recv(sockets[idx], buf, MAXBUFSIZE, 0)) != 0)
send(sockets[idx], buf, n, 0); //TODO: send + while
}
}
if (net_events.lNetworkEvents & FD_WRITE) {
puts("FD_WRITE");
if (net_events.iErrorCode[FD_WRITE_BIT] == 0)
printf("FD_WRITE...(%d)\n", sockets[idx]);
}

if (net_events.lNetworkEvents & FD_CLOSE) {
puts("FD_CLOSE");
if (net_events.iErrorCode[FD_CLOSE_BIT] == 0) {
closesocket(sockets[idx]);
WSACloseEvent(wsaevents[idx]);//5、释放事件所占用的资源
for (i = idx; i < cevents - 1; ++i) {
wsaevents[i] = wsaevents[i + 1];
sockets[i] = sockets[i + 1];
}
--cevents;
}
}
}

WSACleanup();

return 0;
}


源代码2:客户端程序


#include <windows.h>
#include <stdio.h>

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

#define SERV_PORT 9527
#define MAXLINE 128

void exit_msg(const char* msg) {
perror(msg);
exit(0);
}

void str_cli(FILE* fp, int sockfd) {
char buf[MAXLINE];
while (fgets(buf, MAXLINE, fp) != NULL) {
int n = send(sockfd, buf, strlen(buf), 0);
if (recv(sockfd, buf, MAXLINE, 0) == 0)
exit_msg("str_cli readline==0");
fputs(buf, stdout);
}
}

int main(int argc, char* argv[]) {
SOCKET sockfd;
WSADATA wsa;
struct sockaddr_in servaddr;

/*if (argc != 2)
exit_msg("argv != 2");*/

WSAStartup(MAKEWORD(2, 2), &wsa);

sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_port = htons(SERV_PORT);
servaddr.sin_family = AF_INET;
servaddr.sin_addr.S_un.S_addr = inet_addr(/*argv[1]*/"127.0.0.1");

if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
exit_msg("connect error !");
}

str_cli(stdin, sockfd);

closesocket(sockfd);
WSACleanup();

return 0;
}

...全文
39 1 打赏 收藏 举报
写回复
1 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
qingdujun 2019-03-31


我在群里@稀饭 帮忙发现了问题,是一个recv值处理的错误。

只有正常关闭socket,recv才会返回0。其他异常情况下会返回<0的值。
  • 打赏
  • 举报
回复
发帖
其它技术问题

3859

社区成员

C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
帖子事件
创建了帖子
2019-03-31 04:24
社区公告
暂无公告