c - 在 C 中,如何在不关闭/关闭套接字的情况下写入数据后指示 EOF?

标签 c sockets keep-alive

我是 C 套接字编程的新手。我了解到,通过套接字发送数据后,应该关闭关闭 套接字描述符,这会触发将 EOF 发送到另一端。如果没有 EOF,read/recv 会一直阻塞。

现在我想知道是否有可能保持套接字打开以进行进一步的数据传输。从我读到的内容来看,这似乎是人们在建立 keep-alive HTTP 连接时所做的事情。但我无法弄清楚这是如何实现的。

以下代码显示了在客户端写入之后卡住的场景。

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

#define thread_printf(...) printf("[PID %d] ", getpid()); printf(__VA_ARGS__);

int create_socket()
{
  int socket_fd;
  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  if (socket_fd < 0)
    perror("Error opening socket");
  return socket_fd;
}

int listen_port(int portno)
{
  int socket_fd;
  struct sockaddr_in server_addr;

  socket_fd = create_socket();

  memset((void *) &server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(portno);
  server_addr.sin_addr.s_addr = INADDR_ANY;

  if (bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
    perror("Error on binding");

  listen(socket_fd, 5);
  return socket_fd;
}

int connect_port(const char *host, int portno)
{
  int socket_fd;
  struct sockaddr_in proxy_addr;
  struct hostent *proxy;

  socket_fd = create_socket();

  proxy = gethostbyname(host);
  if (proxy == NULL)
    perror("Error no such host");

  proxy_addr.sin_family = AF_INET;
  proxy_addr.sin_port = htons(portno);
  memcpy((void *) &proxy_addr.sin_addr.s_addr, (void *) proxy->h_addr, proxy->h_length);

  if (connect(socket_fd, (struct sockaddr *) &proxy_addr, sizeof(proxy_addr)) < 0)
    perror("Error connecting");

  return socket_fd;
}

int read_socket(int fd, char *buf, int bufsize)
{
  thread_printf("read_socket\n");
  int m = 0;                    /* total number of bytes received */
  int n = 0;                    /* number of bytes received in a single read */

  while (m < bufsize - 1)
  {
    n = read(fd, buf + m, bufsize - m - 1);
    if (n == -1)                /* socket read error */
    {
      perror("Error reading socket");
      break;
    }
    if (n == 0)                 /* socket is closed */
      break;
    m += n;
  }

  if (m >= bufsize)
    perror("Error buffer overflow");

  buf[m] = '\0';
  return m;
}

int write_socket(int fd, char *buf, int len)
{
  thread_printf("write_socket\n");
  int m = 0;
  int n = 0;

  while (m < len)
  {
    n = write(fd, buf + m, len - m);
    if (n == -1) {
      perror("Error socket send");
      break;
    }
    if (n == 0)                 /* socket is closed */
      break;
    m += n;
  }
  thread_printf("m = %d, len = %d\n", m, len);
  return m;
}

int main()
{
  int socket_fd = listen_port(3129);
  if (fork() == 0)              /* client */
  {
    close(socket_fd);
    int client_socket_fd = connect_port("127.0.0.1", 3129);
    int n;
    char *msg = "This is a client request\n";
    char buf[1024];
    memset((void *) buf, 0, 1024);
    n = write_socket(client_socket_fd, msg, strlen(msg));
    thread_printf("client sent: %s\n", msg);
    n = read_socket(client_socket_fd, buf, 1024);
    thread_printf("client received: %s\n", buf);
    close(client_socket_fd);
  }
  else                          /* server */
  {
    struct sockaddr_in client_addr;
    int client_len;
    client_len = sizeof(client_addr);
    int client_socket_fd = accept(socket_fd, (struct sockaddr *) &client_addr, &client_len);
    int n;
    char *msg = "This is a server response\n";
    char buf[1024];
    n = read_socket(client_socket_fd, buf, 1024);
    thread_printf("server received: %s\n", buf);
    n = write_socket(client_socket_fd, msg, strlen(msg));
    thread_printf("server sent: %s\n", msg);
    close(client_socket_fd);
  }

  return 0;
}

最佳答案

在服务器中,您的代码等待读取 1024 个字节,但在客户端中,您仅发送 26 个字节作为 strlen(msg),因此您的服务器永远不会从 read_socket

对于任何套接字客户端-服务器应用程序,您需要为客户端和服务器定义自己的协议(protocol),以决定何时确定已读取所有数据,或者通过确定固定长度的数据包,或者通过将数据长度作为数据本身的一部分

例如您可以决定您的数据将包括前 2 个字节作为数据长度,然后是实际数据

关于c - 在 C 中,如何在不关闭/关闭套接字的情况下写入数据后指示 EOF?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45747973/

相关文章:

java - LocalSocket 写入和刷新以管道错误结束

java - C#-服务器和 Java-客户端 : TCP Socket Communication Issues

java套接字保持 Activity 很慢,重新打开套接字更快

c++ - 读取 Windows 套接字上的 SIO_KEEPALIVE_VALS 字段(用于保持空闲和间隔时间)

c - C、execve 和参数中的 UNIX 简单 shell

c - 为什么我总是得到字符串数组的最后一个元素?

C:当我将一个数组复制到另一个数组时,代码停止工作

c - 使用 Sparse 检查 C 代码

linux - socket::accept 继续返回 EGAIN

http - http非长连接模式有什么用