来自 C 中 sendto() 套接字程序的无效参数

Invalid Argument from sendto() Socket Program in C

我正在尝试制作一个简单的客户端-服务器 API 用于我的两台机器。我制作了这个简单的程序,它使用我制作的功能来测试它。出于某种原因,我的客户端可以很好地发送消息,但我的服务器不能(但是,它从客户端接收消息)。

服务器端输出:

 host name: my_host
 Our port number is: 34440
 Client msg: Client msg
 Send failed: Invalid argument
 Message from Server sent to Client

客户端输出:

 Connection established with server...
 Message from Client sent to Server

服务器端:

#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include "my_socket.h"

int main() {

    server_init();
    char *msg = "Server msg";
    char buffer[100];

    int n = read_from_client((char *)buffer);
    buffer[n] = '[=12=]';
    printf("Client msg: %s\n", buffer);
    write_to_client((char *)msg);
    printf("Message from Server sent to Client \n");   
    return 0;
}

客户端:

   #include <sys/socket.h>
   #include <stdio.h>
   #include <unistd.h>
   #include <fcntl.h>
   #include <pthread.h>
   #include <stdlib.h>
   #include "my_socket.h"

   int main() {

   client_init();
   char *msg = "Client msg";
   char buffer[100];

   write_to_server((char*)msg);
   printf("Message from Client sent to Server \n");
   int n = read_from_server((char *)buffer);
   buffer[n] = '[=13=]';
   printf("Server msg: %s\n", buffer);

   close_socket();  
   return 0;
 }

my_socket.c:

#include "my_socket.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>

   int sockfd1;
   int sockfd2;
   int MAX_BUFF = 1024;
   struct sockaddr_in server;
   struct sockaddr_in client;
   struct hostent *host;

   ssize_t write_to_server(const void *buffer){
      int bytes_sent, server_size = sizeof(server), buf_len = strlen(buffer);
      if ((bytes_sent = sendto(sockfd2, buffer, buf_len, 0, 
            (const struct sockaddr *)&server, server_size)) < 0){
     perror("Send failed");
      }
      return bytes_sent;
   }

   ssize_t write_to_client(const void *buffer){
      int bytes_sent, client_size = sizeof(client), buf_len = strlen(buffer);
      if ((bytes_sent = sendto(sockfd1, buffer, buf_len, 0, 
            (const struct sockaddr *)&client, client_size)) < 0){
     perror("Send failed");
      }
      return bytes_sent;
   }

   int read_from_server(void *buffer){
      int bytes_rcv, len;
      if ((bytes_rcv = recvfrom(sockfd2, buffer, MAX_BUFF, MSG_WAITALL, 
                   (struct sockaddr *)&server, &len)) < 0){
     perror("Read failed");
      }
      return bytes_rcv;
   }

   int read_from_client(void *buffer){
      int bytes_rcv, len;
      if ((bytes_rcv = recvfrom(sockfd1, buffer, MAX_BUFF, MSG_WAITALL, 
                   (struct sockaddr *)&client, &len)) < 0){
     perror("Read failed");
      }
      return bytes_rcv;
   }


   void close_socket() {
      close(sockfd1);
      close(sockfd2);
   }

   void server_init(){
      if ( (sockfd1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
     perror("socket creation failed");
      }
      char name[1024];
      name[1023] = '[=14=]';
      gethostname(name, 1023);
      printf("host name: %s \n", name);

      host = gethostbyname("my_host");
      if(host == NULL){
     perror("Host is null");
     exit(0);
      }

      bzero((char *)&server, sizeof(server));
      bzero((char *)&client, sizeof(client));

      server.sin_family          = AF_INET;
      bcopy((char *)host->h_addr, 
        (char *)&server.sin_addr.s_addr, host->h_length);
      //server.sin_port            = 0; 
      server.sin_port            = htons(34440);

      if ( (bind(sockfd1, (struct sockaddr *)&server, sizeof(server) ) ) < 0 ){
     perror("bind failed");
      } 
      socklen_t len = sizeof(server);
      if (getsockname(sockfd1, (struct sockaddr *)&server, &len) == -1){
     perror("getsockname");
      }else{
     printf("Our port number is: %d\n", ntohs(server.sin_port));
      }
   }

   void client_init(){

      if ( (sockfd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
     perror("socket creation failed");
      }

      host = gethostbyname("my_host");
      if(host == NULL){
     perror("Host is null");
     exit(0);
      }

      bzero((char *)&server, sizeof(server));

      server.sin_family       = AF_INET;
      bcopy((char *)host->h_addr, 
        (char *)&server.sin_addr.s_addr, host->h_length);
      //server.sin_port = 0; 
      server.sin_port = htons(34440);

      if(connect(sockfd2, (struct sockaddr *)&server, sizeof(server)) == 0){
     printf("Connection established with server...\n");
      }

   }

my_socket.h:

#ifndef MY_SOCKET
#define MY_SOCKET
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h>
#include <netdb.h>


extern int sockfd1;
extern int sockfd2;
extern int MAX_BUFF;
extern struct sockaddr_in server;
extern struct sockaddr_in client;
extern struct hostent *host;


// Send a message over the socket  
ssize_t write_to_server(const void *buffer);
ssize_t write_to_client(const void *buffer);

// Blocks until told it's ready; receives bytes from socket 
int read_from_server(void *buffer);
int read_from_client(void *buffer);   

// Close the socket
void close_socket();

void server_init();

void client_init();      


#endif

欢迎任何建议或批评。提前致谢。

至少有一个问题是您没有在 read_from_client 中初始化 len 变量。 recvfrom 的手册页部分(强调)说:

... addrlen is a value-result argument. Before the call, it should be initialized to the size of the buffer associated with src_addr. Upon return, addrlen is updated to contain the actual size of the source address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.

这意味着,作为一个未初始化的堆栈变量,len具有不确定的值。可能为零,但至少小于 sizeof(struct sockaddr_in)。结果,client 没有被 recvfrom.

正确填写

就在 recvfrom 之前,您应该用以下方式初始化它:

len = sizeof(client);

在客户端,write_to_serverread_from_server 不需要使用 recvfromsendto,因为您已经在套接字上完成了 connect。他们可以简单地使用 recvsend,因为远程套接字端点已经由 connect 建立。我相信对于已连接的套接字,地址只是被忽略了,但我现在找不到记录的位置。

(无论如何,如果您 继续在客户端使用 recvfrom,您应该在那里进行相同的 len 初始化。)