Winsock 回显服务器端口

Winsock echo server port

我正在尝试将这个简单的 TCP 回显程序 (https://github.com/mafintosh/echo-servers.c/blob/master/tcp-echo-server.c) 移植到 Windows 下用于教学目的。 我的改编编译和运行,但它不起作用:

**** 编辑:监听电话不知何故被切断了。感谢雷米 ****

客户端已连接,但未收到任何回显。

移植代码如下(报错信息是意大利语,不过应该很清楚):

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

#define BUFFER_SIZE 1024
void on_error(char *s) { fprintf(stderr,"%s\n",s); fflush(stderr); exit(1); }

int main(int argc, char *argv[]) {
    WSADATA wsadata; 
    int server_fd, client_fd, err;
    struct sockaddr_in server, client;
    char buf[BUFFER_SIZE];

    int port = 6666; 
    int risultato = WSAStartup(MAKEWORD(2,2),&wsadata);
    if (risultato != NO_ERROR)
        {fprintf(stderr,"Errore in WSAStartup");fflush(stderr); exit(1);}

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) on_error("Non ho potuto creare il socket\n");    
    server.sin_family = AF_INET; 
    server.sin_port = htons(port); 
    server.sin_addr.s_addr = htonl(INADDR_ANY); 

    const char opt_val = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof opt_val);
    /** bind & listen **/
    err = bind(server_fd, (struct sockaddr *) &server, sizeof(server));
    if (err < 0) on_error("Non ho potuto fare il bind del socket\n");   
    err = listen(server_fd, 128);
    if (err < 0) on_error("Non ho potuto mettermi in ascolto sul socket\n");
    printf("SERVER LISTENING ON PORT %d\n", port);

    while (1) {
      int client_len = sizeof(client);
      do {
      client_fd = accept(server_fd, (struct sockaddr *) &client, &client_len);
      } while ( client_fd = SOCKET_ERROR);

      if (client_fd < 0) on_error("Non riesco a stabilire una nuova connessione\n");

      while (1) {
        int read = recv(client_fd, buf, BUFFER_SIZE, 0);

        if (!read) break;
        if (read < 0) on_error("Errore nella lettura dal client\n");

        err = send(client_fd, buf, read, 0);
        if (err < 0) on_error("Errore nella scrittura verso il client\n");
    }
  }

    WSACleanup();
    return 0;
}

您正在调用 bind() 来设置监听端口,但您没有调用 listen() 在进入 accept() 循环之前实际开始监听该端口。

一旦你修正了这个错误,你的 accept() 循环就会被打破,因为即使 accept() 成功了,它也会强制 client_fdSOCKET_ERROR。当需要使用 == 比较运算符时,您的 while() 条件正在使用 = 赋值运算符。你应该检查 INVALID_SOCKET 而不是 SOCKET_ERROR.

话虽如此,还有一些其他事情需要考虑:

  • WinSock 没有使用int 来表示套接字,而是使用SOCKET 来表示,这是一个UINT_PTR。检查无效套接字句柄时,不要使用 < 0,而应使用 == INVALID_SOCKET

  • 大多数套接字功能 return 通过 WSAGetLastError() 的错误代码(WSAStartup() 是一个例外)。养成使用它的习惯,并在输出消息中报告错误代码,这样您就知道失败的原因。

  • SO_REUSEADDR 需要 BOOL 值,而不是 char 值。 BOOLint 的类型定义,因此是 4 个字节。

  • 并非所有套接字错误都是致命的,因此如果 recv()/send() 操作因非致命错误而失败,您不应该终止整个服务器。

  • send() 不能保证发送您要求发送的所有内容,因此您应该考虑到这一点。

  • 使用完后不要忘记关闭已接受的客户端套接字。

试试这个:

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

#define BUFFER_SIZE 1024

void on_error(char *s, int *errCode = NULL)
{
    int err = (errCode) ? *errCode : WSAGetLastError();
    fprintf(stderr, "%s: %d\n", s, err);
    fflush(stderr);
    exit(1);
}

int main(int argc, char *argv[])
{
    WSADATA wsadata; 
    SOCKET server_fd, client_fd;
    struct sockaddr_in server, client;
    int port = 6666, err; 
    char buf[BUFFER_SIZE];

    err = WSAStartup(MAKEWORD(2,2), &wsadata);
    if (err != 0)
        on_error("Errore in WSAStartup", &err);

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == INVALID_SOCKET)
        on_error("Non ho potuto creare il socket");

    memset(&server, 0, sizeof(server)); 
    server.sin_family = AF_INET; 
    server.sin_port = htons(port); 
    server.sin_addr.s_addr = INADDR_ANY; 

    /** bind & listen **/
    const BOOL opt_val = TRUE;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt_val, sizeof(opt_val));
    err = bind(server_fd, (struct sockaddr *) &server, sizeof(server));
    if (err == SOCKET_ERROR)
        on_error("Non ho potuto fare il bind del socket");
    err = listen(server_fd, 1);
    if (err == SOCKET_ERROR)
        on_error("Non ho potuto mettermi in ascolto sul socket");

    printf("SERVER LISTENING ON PORT %d\n", port);

    while (1)
    {
        int client_len = sizeof(client);
        client_fd = accept(server_fd, (struct sockaddr *) &client, &client_len);

        if (client_fd == INVALID_SOCKET)
            on_error("Non riesco a stabilire una nuova connessione");

        bool keepLooping = true;
        do
        {
            int read = recv(client_fd, buf, BUFFER_SIZE, 0);

            if (read == 0)
                break;

            if (read == SOCKET_ERROR)
            {
                err = WSAGetLastError();
                if ((err != WSAENOTCONN) && (err != WSAECONNABORTED) && (err == WSAECONNRESET))
                    on_error("Errore nella lettura dal client", &err);
                break;
            }

            char *pbuf = buf;
            do
            {
                int sent = send(client_fd, pbuf, read, 0);
                if (sent == SOCKET_ERROR)
                {
                    err = WSAGetLastError();
                    if ((err != WSAENOTCONN) && (err != WSAECONNABORTED) && (err == WSAECONNRESET))
                        on_error("Errore nella scrittura verso il client", &err);

                    keepLooping = false;
                    break;
                }

                pbuf += sent;
                read -= sent;
            }
            while (read > 0);
        }
        while (keepLooping);

        closesocket(client_fd);
    }

    WSACleanup();
    return 0;
}

对不起,但是

   while (client_fd = SOCKET_ERROR)

你不是说吗?

   (client_fd == SOCKET_ERROR)