【问题标题】:Simple winsock server acting unreliablely简单的winsock服务器行为不可靠
【发布时间】:2013-06-04 04:25:41
【问题描述】:

我有以下用纯 C 语言编写的简单 winsock 服务器:

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

#define NETWORK_ERROR -1
#define NETWORK_OK     0

int IP = INADDR_ANY;
int port = 8888;

SOCKET listeningSocket;
SOCKET client;

void error(const char *);
void error(const char *functionName) {
    char errorMsg[92];
    ZeroMemory(errorMsg, 92);

    sprintf(errorMsg, "Call to %s returned error %d!", (char *)functionName, WSAGetLastError());

    MessageBox(NULL, errorMsg, "socketIndication", MB_OK);

    closesocket(client);
    closesocket(listeningSocket);
    WSACleanup();
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShow) {

    WSADATA wsaData;
    int nret;

    WSAStartup(MAKEWORD(1, 1), &wsaData);

    char hostName[80];
    if(gethostname(hostName, sizeof(hostName)) == SOCKET_ERROR) {
        error("gethostname()");
        return NETWORK_ERROR;
    }

    printf("Started Server\n");
    printf("Running on: %s\n", hostName);

    listeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if(listeningSocket == INVALID_SOCKET) {
        error("socket()");
        return NETWORK_ERROR;
    }

    SOCKADDR_IN serverInfo;

    serverInfo.sin_family = AF_INET;
    serverInfo.sin_addr.s_addr = INADDR_ANY;

    serverInfo.sin_port = htons(port);

    nret = bind(listeningSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));

    if(nret == SOCKET_ERROR) {
        error("bind()");
        return NETWORK_ERROR;
    }

    while(client != INVALID_SOCKET) {
        nret = listen(listeningSocket, 10);
        printf("Listening for incoming requests\n");

        if(nret == SOCKET_ERROR) {
            error("listen()");
            return NETWORK_ERROR;
        }

        client = accept(listeningSocket, NULL, NULL);

        char buffer[256];
        ZeroMemory(buffer, 256);

        strcpy(buffer, "Pretend this is important data.");

        nret = send(client, buffer, strlen(buffer), 0);

        if(nret == SOCKET_ERROR) {
            error("send()");
            return NETWORK_ERROR;
        }

        printf("Sent some data\n");

        closesocket(client);
    }

    error("accept()");
    return NETWORK_ERROR;
}

大部分内容来自本教程:

http://johnnie.jerrata.com/winsocktutorial/

但是,服务器似乎很受欢迎。当我在浏览器中访问 http://[My IP]:8888/ 时,有一半的时间我会得到“假装这是重要数据”的响应。正如预期的那样,但是另一半时间我得到“页面加载时与服务器的连接已重置”。或“Firefox 无法与 [My IP]:8888 的服务器建立连接。”。

那么我的代码有什么问题会导致这种情况吗?

【问题讨论】:

  • 嗯,一个问题可能是您正在使用 Firefox 测试它,使用 http。您的代码在发送响应时未使用 http 协议。您可以尝试使用 telnet 或类似的方式进行测试。
  • 它几乎符合 HTTP/0.9 的要求,但它在发送之前不会读取来自客户端的请求。如果服务器在包含客户端请求的数据包到达之前完成写入响应并关闭套接字,则到达已关闭套接字的数据包将生成重置。

标签: c winsock


【解决方案1】:

listen() 的调用应该在循环之外。循环中唯一需要的套接字调用是 accept() 来获取客户端套接字,以及读取、写入和最终关闭客户端套接字。

此外,如果您希望程序与 Firefox 一起使用,您必须实现 HTTP 协议的相关部分,http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

【讨论】:

  • 这个,除了 Wumpus W. Wumbley 建议的工作之外!好吧,有 1% 的时间它会随机显示错误,但除此之外没问题。谢谢。
  • 我还注意到,使用更隐蔽的端口(如 5473)而不是传统的端口 80 或 8888 可以大大降低这些错误的频率。
猜你喜欢
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-30
  • 2015-03-02
  • 1970-01-01
  • 2015-12-18
  • 1970-01-01
相关资源
最近更新 更多