c - socket connect() 返回 errno EINVAL

标签 c linux sockets

我正在开发一个用于 C 套接字编程的小型演示应用程序,但在连接到本地计算机上托管的服务器应用程序时遇到了问题。当我调用 connect() 时,我返回 errno 22,它是 EINVAL,我无法弄清楚哪个参数无效以及为什么它无效。

我不确定是什么导致了这个错误。我已经检查了我所做的所有调用的手册页,并查看了大约六个教程,据我所知,我似乎没有遗漏任何部分。

(顺便说一句,我正在使用 gcc 来编译应用程序)

谁能帮帮我?

客户端.c

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>

#define ARGBUF_SIZE 256
#define MAX_BUF 1024

void
post_error(const char* inMsg)
{
fprintf(stderr, "%s\n", inMsg);
perror("errno is ");
fflush(stderr);
exit(-1);
}

int
open_tcp(void)
{
return socket(PF_INET, SOCK_STREAM, 0);
}

int
open_udp(void)
{
return socket(PF_INET, SOCK_DGRAM, 0);
}

int
open_connection(const char* connectionType, struct sockaddr_in* target)
{
int handle = -1;

if (strcmp(connectionType, "tcp") == 0)
    handle = open_tcp();
else if (strcmp(connectionType, "udp") == 0)
    handle = open_udp();
else
    post_error("error: invalid arguments - connection type can only be either \"tcp\" or \"udp\"");

/* attempt connection */
int result = connect(handle, (struct sockaddr*)&target, sizeof(target));

/* inspect errno for more information on the error */
/*
 * this switch is unneeded since perror dumps the string for errno
 * but it is useful for debugging
 */
fprintf(stdout, "errno is ");
switch (errno)
{
case EACCES:
    fprintf(stdout, "EACCESS");
    break;
case EPERM:
    fprintf(stdout, "EPERM");
    break;
case EADDRINUSE:
    fprintf(stdout, "EADDRINUSE");
    break;
case EAFNOSUPPORT:
    fprintf(stdout, "EAFNOSUPPORT");
    break;
case EAGAIN:
    fprintf(stdout, "EAGAIN");
    break;
case EALREADY:
    fprintf(stdout, "EALREADY");
    break;
case EBADF:
    fprintf(stdout, "EBADF");
    break;
case ECONNREFUSED:
    fprintf(stdout, "ECONNREFUSED");
    break;
case EFAULT:
    fprintf(stdout, "EFAULT");
    break;
case EINPROGRESS:
    fprintf(stdout, "EINPROGRESS");
    break;
case EINTR:
    fprintf(stdout, "EINTR");
    break;
case EISCONN:
    fprintf(stdout, "EISCONN");
    break;
case ENETUNREACH:
    fprintf(stdout, "ENETUNREACH");
    break;
case ENOTSOCK:
    fprintf(stdout, "ENOTSOCK");
    break;
case ETIMEDOUT:
    fprintf(stdout, "ETIMEDOUT");
    break;
default:
    fprintf(stdout, "unknown error(%d)", errno);
    break;
}
fprintf(stdout, "\n");
fflush(stdout);

if (result < 0)
    post_error("error: invalid arguments? - connection failed");

printf("connection made");
return handle;
}

int
main(int argc, char* argv[])
{
int handle;
struct sockaddr_in target;

if (argc != 4)
    post_error("usage: socket_client [tcp | udp] [server ip] [port number]");

/* argv[0] is expected to be sockcn the name of this executable */
memset(&target, 0, sizeof(target));
target.sin_family = AF_INET;
in_addr_t addr;
int result = inet_aton(argv[2], &addr);
if (result == INADDR_NONE)
    post_error("error: invalid arguments - failed to convert ip address from string format");
target.sin_addr.s_addr = addr;
target.sin_port = htons(atoi(argv[3]));

handle = open_connection(argv[1], &target);

char buffer[MAX_BUF];
while (1)
{
    printf("> ");

    /* wait for input from user in faux-prompt and send to connection */
    fgets(buffer, MAX_BUF, stdin);

    if (strcmp(buffer, "exit\n") == 0)
        break;

    unsigned int len = strlen(buffer);
    if (send(handle, buffer, len, 0) != len)
        post_error("error: bytes sent is not the same as the size of the message");
}

close(handle);
return 0;
}

服务器.c

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#define MAX_BUF 256

void
post_error(const char* inMsg)
{
fprintf(stderr, "%s", inMsg);
perror("errno is ");
exit(-1);
}

void
handle_client(int client)
{
char buffer[MAX_BUF];
int received = -1;

/* receive message */
received = recv(client, buffer, MAX_BUF, 0);
if (received < 0)
    post_error("error: connection - failed to receive initial bytes from client");

while (received > 0)
{
    printf("%s", buffer);
    received = recv(client, buffer, MAX_BUF, 0);

    if (received < 0)
        post_error("error: connection - failed to received pending bytes from client"); 
}

close(client);
}

int
open_tcp(void)
{
return socket(AF_INET, SOCK_STREAM, 0);
}

int
open_udp(void)
{
return socket(AF_INET, SOCK_DGRAM, 0);
}

int
main(int argc, char* argv[])
{
int serverHandle;
int clientHandle;
struct sockaddr_in server;
struct sockaddr_in client;

if (argc != 3)
    post_error("usage: server [tcp or udp] [port number]");

int udp;
if (strcmp(argv[1], "tcp") == 0)
{
    udp = 0;
    serverHandle = open_tcp();
}
else if (strcmp(argv[1], "udp") == 0)
{
    udp = 1;
    serverHandle = open_udp();
}
else
{
    post_error("error: invalid arguments - first argument must be either \"tcp\" or \"udp\"");
}

/* construct the server struct */
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // htonl(INADDR_ANY);
server.sin_port = htons(atoi(argv[2]));

/* bind is used for server compared to connect for clients */
if (bind(serverHandle, (struct sockaddr*)&server, sizeof(server)) < 0)
    post_error("error: failed to bind to target port");

if (!udp)
{
    /* listen to start receiving messages */
    if (listen(serverHandle, 1) < 0)
        post_error("error: failed to listen on bound port");
}

fprintf(stdout, "server initialized.\nwaiting for messages...\n");
fflush(stdout);

/* now just wait for messages to come in */
/* the if should really be outside the while to avoid checking 'udp' every iteration but this seems fairly clear of the intention */
while (1)
{
    if (udp)
    {
        char buffer[MAX_BUF];
        socklen_t len = sizeof(client);
        ssize_t received = recvfrom(serverHandle, buffer, MAX_BUF, 0, (struct sockaddr*)&client, &len);

        fprintf(stdout, "> %s", buffer);
        fflush(stdout);
    }
    else
    {
        /* wait for connection */
        socklen_t len = sizeof(client);
        if (clientHandle = accept(serverHandle, (struct sockaddr*)&client, &len) < 0)
            post_error("error: failed to accept client connection");

        fprintf(stdout, "client connected: %s\n", inet_ntoa(client.sin_addr));
        fflush(stdout);
        handle_client(clientHandle);
    }
}
}

服务器使用 ./server tcp 65000 运行 客户端使用 ./client tcp 65000 运行

最佳答案

错误在这一行:

int result = connect(handle, (struct sockaddr*)&target, sizeof(target));

target 已经是您正在获取地址的指针类型。尝试

int result = connect(handle, (struct sockaddr*)target, sizeof(*target));

请注意微妙的sizeof(*target)

关于c - socket connect() 返回 errno EINVAL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24141307/

相关文章:

c - 抽象解释器如何工作?

node.js - systemd 服务处于非事件状态(已死)

linux - 在 Thunar 中远程创建自定义操作

Java 服务器套接字故障

javascript - 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

python - 位操作给出错误的输出

c - MQOPEN 给出错误 2085,这是我以前没有的

c - 矩阵与线程相乘(每个线程做单次乘法)

linux - 如何克隆位于连接到互联网的 Mac 上的 git 存储库?

java - 通过 TCP/IP 接收对象