首页 > 解决方案 > TCP 服务器套接字未通过 addrinfo 方法侦听

问题描述

所以这里是代码,代码成功编译......

#include <stdio.h> // for printf
#include <linux/if_tun.h> //for IFF_TUN
#include <sys/socket.h> //socket, struct sockaddr_in
#include <fcntl.h> // for O_RDWR macros
#include <string.h> //for strcpy
#include <unistd.h> //for read();
#include <netdb.h> //for struct sockaddr
#include <net/if.h> //struct ifreq and IFNAMSIZ and other macros
#include <errno.h>
#include <stdlib.h>

// _check: error handler
static int _check(int retval, const char *msg)
{
    if(retval == -1)
    {
        fprintf(stderr, "%s: %s\n", msg, strerror(errno));
        exit(EXIT_FAILURE);
    }
    return retval;
}


int tcp_listen_sock(int listen_connection)
{
    /*-------------------------socket-----------------------*/
    int sock, tcp_sock;
    struct addrinfo hints, *result;
    struct sockaddr *addrin;

    memset(&hints ,0 , sizeof(hints));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    const char *host;

    host = "0.0.0.0";

    _check(getaddrinfo(host, NULL, &hints, &result), "getaddrinfo");

    if (result->ai_family == AF_INET)
    ((struct sockaddr_in *)result->ai_addr)->sin_port = htons(5678);
  else if (result->ai_family == AF_INET6)
    ((struct sockaddr_in6 *)result->ai_addr)->sin6_port = htons(5678);
  else {
    fprintf(stderr, "unknown ai_family %d", result->ai_family);
    freeaddrinfo(result);
    return -1;
  }
    memcpy(addrin, result->ai_addr, result->ai_addrlen);
//  *client_len = result->ai_addrlen;

    _check((sock = socket(AF_INET, SOCK_STREAM, 0)), "socket");
    
    struct ifreq ifr;

    memset(&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "enp0s3");
    _check(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)), "setsockopt");

    int flags;
    if((flags = fcntl(sock, F_GETFL)) != -1)
    {
        fcntl(sock, F_SETFL, flags | O_NONBLOCK);
    }
    else
    perror("socket fcntl");

            _check(bind(sock,result->ai_addr, result->ai_addrlen), "tcp bind");


    int len = sizeof(struct sockaddr);
    _check(listen(sock, listen_connection), "listen");
    tcp_sock = accept(sock, result->ai_addr, &result->ai_addrlen );
    
    printf("now listening on tcp!\n");
    
    return tcp_sock;
    
}

int main(int argc, char **argv)
{
    printf("Starting program\n");
    int tcp = tcp_listen_sock(5);
   printf("ending program\n");
    return 0;
}

和 ,

输出

Starting program
now listening on tcp!
ending program

但服务器套接字实际上并没有在听......

预期输出:

Starting program
now listening on tcp!
read...
write...
read...
write...
read...
write..

我无法弄清楚我缺少什么,我知道我还没有实现读、写,但是当服务器套接字似乎工作正常并正常监听时我会这样做。

注意:我在 linux 中执行此操作(特别是 ubuntu)

任何帮助将不胜感激...

标签: csocketsservertcp

解决方案


调用 getaddrinfo 来初始化本地列表套接字似乎有点过头了。

从这个开始。这是一个简单的“创建侦听套接字并等待传入​​的 TCP 连接”代码示例。

int tcp_socket_listen(int listen_connection)
{
     struct sockaddr_in addr = {0};
     sockaddr_in addrRemote = {0};
     socklen_t sizeRemote = 0;
     int tcp_socket = -1;

     s = socket(AF_INET, SOCK_STREAM, 0);
     _check(s, "socket");

     addr.sin_family = AF_INET;
     addr.sin_port = htons(5678);
     _check(bind(s, (sockaddr*)&addr, sizeof(addr)), "bind");

     _check(listen(sock, listen_connection), "listen");

     sizeRemote = sizeof(addrRemote);
     tcp_sock = accept(s, (sockaddr*)&addrRemote, &sizeRemote);

     _check(tcp_sock, "accept");

     printf("now listening on TCP\n");

     return tcp_sock;
}

现在,如果您想绑定到特定适配器(例如“enp0s3”)而不是默认适配器(“所有适配器”)或需要 IPV6 支持,您可以在此处仔细阅读我在 github 上的示例代码,GetSocketAddressForAdapter并将该地址用于bind调用上面的默认addr地址。它是 C++,但您可以通过一些工作将其移植到直接 C。


推荐阅读