c - 发送和接收不一致

标签 c sockets tcp

好吧,伙计们,我已经连续工作了两天,寻找错误并寻找去年的解决方案和其他软件,但发现

我的问题是,我需要编写一个相当简单的服务器客户端应用程序,在其中接收响应并回复它们。我编写了较小的程序来演示我的问题。

在您提示发送和接收缺乏完整性之前,要检查的发送和接收不为< 0。我知道我必须检查这一点。

common.h 只是所有输入和静态变量的 header 。

// guard block:
#ifndef COMMON_H
#define COMMON_H

// default hostname and port:
#define DEFAULT_HOST    "localhost"
#define DEFAULT_PORT    "1280"

#include <stdarg.h>
#include <ctype.h> 

// IO, C standard library, POSIX API, data types:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <limits.h>

// Sockets, TCP, ... :
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>

// Assertions, errors, signals:
#include <assert.h>
#include <errno.h>
#include <signal.h>

static struct addrinfo *ai = NULL;      // stores address information
static int sockfd = -1;                 // socket file descriptor
static int connfd = -1;                 // connection file descriptor

void terminate(int sig);
void init_signal_handler(void);
void free_ressources(void);
void error(char* format, ...);

void terminate(int sig) {
  error("Caught signal %d. Terminating...\n",sig);
}

void init_signal_handler(void) {
  struct sigaction sa;
  sa.sa_handler = terminate;
  if (-1 == sigemptyset(&(sa.sa_mask))) {
    error("sigemptyset()");
  }
  if (-1 == sigaction(SIGINT, &sa, NULL)) {
    error("sigaction()");
  }
  if (-1 == sigaction(SIGTERM, &sa, NULL)) {
    error("sigaction()");
  }
}

void error(char *format, ...) {
  va_list arg;

  va_start (arg, format);
  (void) vfprintf (stderr, format, arg);
  va_end (arg);

  free_ressources();

  exit(EXIT_FAILURE);
}

void free_ressources(void) {
  (void) printf("Freeing all ressources...\n");
  if(sockfd != -1) close(sockfd);
  if(connfd != -1) close(connfd);
  freeaddrinfo(ai);
}
#endif // COMMON_H

这是客户端

#include "common.h"

static char *port = DEFAULT_PORT;
static char *host = DEFAULT_HOST;

int main(int argc, char *argv[]) {
  int s;
  struct addrinfo hints, *rp;
  memset(&ai, 0, sizeof(hints));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  s = getaddrinfo(host, port, &hints, &ai);
  if(s != 0) error("Couldn't get address info...\n");

  for (rp=ai; rp != NULL; rp=rp->ai_next) {
      sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
      if(sockfd == -1) continue;
      if((connfd = connect(sockfd, rp->ai_addr, rp->ai_addrlen)) != -1) break;
      close(sockfd);
  }

  if(rp == NULL) error("Couldn't connect...\n");

  uint16_t msg = 0xF0F0;
  uint8_t msg_r = 0x00;
  for(int i = 0; i < 10; ++i) {
    (void) fprintf(stdout, "Sending message %#X\n", msg);
    send(sockfd, &msg, 2, MSG_CONFIRM);
    recv(connfd, &msg_r, 1, MSG_CONFIRM);
    (void) fprintf(stdout, "Recieved from Server %#X\n", msg_r);
    msg+=1;
  }
  free_ressources();
}

这是服务器

#include "common.h"

static char *port = DEFAULT_PORT;

int main(int argc, char *argv[]) {
  struct addrinfo hints;
  memset(&ai, 0, sizeof(hints));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  int res = getaddrinfo(NULL, port, &hints, &ai);
  if(res != 0) error("Failed to get addr info: %s\n", gai_strerror(res));

  sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  if(sockfd == -1) error("Couldn't create a socket\n");

  int val = 1;
  res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
  if(res == -1) error("Socket options couldn't be set\n");

  res = bind(sockfd, ai->ai_addr, ai->ai_addrlen);
  if(res == -1) error("Socket binding failed\n");

  res = listen(sockfd, 1);
  if(res == -1) error("Listener setup failed\n");

  connfd = accept(sockfd, NULL, NULL);
  if(connfd == -1) error("Connect failed\n");

  uint8_t msg_s = 0x00;
  uint16_t msg = 0x0000;
  for(int i = 0; i < 10; ++i) {
    msg_s+=1;
    recv(connfd, &msg, 2, MSG_CONFIRM);   
    (void) fprintf(stdout, "Recieved from Client %#X\n", msg);
    (void) fprintf(stdout, "Sending %#X\n", msg_s);
    send(sockfd, &msg_s, 1, MSG_CONFIRM);
  }
  free_ressources();
}

好吧,我对此有几个问题。

  1. 如果我朝一个方向执行服务器客户端应用程序,例如仅客户端发送且仅服务器接收,则一切都会一如既往地顺利且符合预期。然而,当我像这里一样将其混合时,事情就会发生变化。我知道 TCP 是一种没有固定“包”数量的流协议(protocol),但我也可以理解如何在最多只需要 2 个字节的情况下实现它。我可能会尝试一次只接收 1 个字节,如果需要 2 个字节,则在循环中执行此操作,但为什么呢?为什么在单车道模式下一切都很好,而在混合模式下却一团糟?

  2. 我尝试使用 recv 并相应地发送到其手册页,因此将它们与套接字一起使用。然而我不知道为什么,但每当我尝试将recv与sock_fd一起使用时,它就不起作用,但另一边的conn_fd却可以。但我到处都看到我显然应该使用 sock_fd。

这是我混合接收和发送时的输出

服务器的输出

Recieved from Client 0XF0F0
Sending 0X1

客户端的输出

Sending message 0XF0F0
Recieved from Server 0
Sending message 0XF0F1
Recieved from Server 0
Sending message 0XF0F2
Recieved from Server 0
Sending message 0XF0F3
Recieved from Server 0
Sending message 0XF0F4
Recieved from Server 0
Sending message 0XF0F5
Recieved from Server 0
Sending message 0XF0F6
Recieved from Server 0
Sending message 0XF0F7
Recieved from Server 0
Sending message 0XF0F8
Recieved from Server 0
Sending message 0XF0F9
Recieved from Server 0
Freeing all ressources...

总之,我知道这可能是一个愚蠢而简单的问题,但为什么会这样呢?为什么服务器在发送第一条消息时就崩溃了,而客户端却将消息扔进了虚空。

感谢您的提前答复,我真的需要解决这个问题。

最佳答案

您有一些小问题和一些大问题:

小:

  • 您不会影响 hints 中的 ai_protocol,但当 hintshints 时,getaddrinfo() 需要它不NULL
  • 您使用 connect() 的返回值作为文件描述符,但它是一个错误代码号。您必须在客户端中使用 socket() 返回的文件描述符,或在服务器中使用 accept() 返回的文件描述符。
  • 在服务器中使用 send() 时使用了错误的文件描述符。您不应该在处理 SOCK_STREAM 套接字类型中的连接的文件描述符上发送数据。
  • getaddrinfo() 返回一个列表,您应该迭代它,但您假设总是有一个结果,但它们可能是零个或多个。
  • hints 已初始化,您可以使用 memset() 调用未定义的行为,因为 sizeof(struct addrinfo) > sizeof(struct addrinfo *) 所以当你在ai上写零时,你就出界了(全局...全局无处不在)

大:

  • 您毫无理由地使用全局
  • 您一行声明多个变量。
  • 您毫无理由地使用全局
  • 您没有验证所有系统调用错误!
  • 您毫无理由地使用全局
<小时/>
// server and client
struct addrinfo hints = {
  .ai_family = AF_INET,
  .ai_socktype = SOCK_STREAM,
  .ai_flags = AI_PASSIVE,
  .ai_protocol = IPPROTO_TCP,
};
// server
if (send(connfd, &msg_s, 1, MSG_CONFIRM) == -1) {
  // error
}
// client
if (recv(sockfd, &msg_r, 1, MSG_CONFIRM) == -1) {
  // error
}

关于c - 发送和接收不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49866247/

相关文章:

tcp - 服务器比使用 TCP 的客户端花费更多时间

c - 监听 TCP 端口时没有任何反应

arrays - 如何检查直线多边形是否相交

复制到用户 : treating more data

c++ - 具有 "aggressive"可变语义的 C 和 C++ 编译器

spring - 是否有任何 spring 集成 tcp-inbound-channel-adapter 示例?

javascript - 检查数组中是否存在键并替换其值

c++ - 通过 UDP 套接字发送数据

mysql - 如何从 Wireshark 文件中查找(解码)PostgreSQL 查询?

tcp - DNS二级域名查询