Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C语言中,在不关闭套接字的情况下,如何在写入数据后指示EOF?_C_Sockets_Keep Alive - Fatal编程技术网

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

在C语言中,在不关闭套接字的情况下,如何在写入数据后指示EOF?,c,sockets,keep-alive,C,Sockets,Keep Alive,我是C套接字编程新手。我了解到,通过套接字发送数据后,应该关闭或关闭套接字描述符,这将触发发送到另一端的EOF。如果没有EOF,read/recv会一直阻塞 现在我想知道是否有可能保持套接字打开以进行进一步的数据传输。从我所读到的内容来看,这似乎是人们在建立保持活动的HTTP连接时所做的事情。但我不知道这是如何实现的 下面的代码显示了该场景,该场景在客户机的写入后卡住 #include <stdio.h> #include <string.h> #include <

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

现在我想知道是否有可能保持套接字打开以进行进一步的数据传输。从我所读到的内容来看,这似乎是人们在建立保持活动的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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义线程_printf(…)printf(“[PID%d]”,getpid());printf(_VA_ARGS__;);
int create_socket()
{
int-socket_-fd;
socket\u fd=socket(AF\u INET,SOCK\u STREAM,0);
如果(插座fd<0)
perror(“错误打开插座”);
返回插座;
}
int侦听_端口(int端口号)
{
int-socket_-fd;
服务器地址中的结构sockaddr\u;
socket_fd=创建_socket();
memset((void*)和服务器地址,0,sizeof(服务器地址));
服务器地址sin家庭=AF网络;
服务器地址sin\u端口=htons(端口号);
server\u addr.sin\u addr.s\u addr=INADDR\u ANY;
if(绑定(socket\u fd,(struct sockaddr*)和服务器地址,sizeof(服务器地址))<0
perror(“绑定错误”);
听(插座fd,5);
返回插座;
}
int connect_端口(常量字符*主机,int端口号)
{
int-socket_-fd;
代理地址中的结构sockaddr\u;
结构宿主*代理;
socket_fd=创建_socket();
proxy=gethostbyname(主机);
if(proxy==NULL)
perror(“无此类主机错误”);
代理地址sin家庭=AF\u INET;
代理地址sin端口=htons(端口号);
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(“错误连接”);
返回插座;
}
int read_插槽(int fd、char*buf、int bufsize)
{
线程printf(“读取套接字”);
int m=0;/*接收的总字节数*/
int n=0;/*单次读取中接收的字节数*/
而(m=bufsize)
perror(“错误缓冲区溢出”);
buf[m]='\0';
返回m;
}
int-write_套接字(int-fd、char*buf、int-len)
{
线程printf(“写入套接字”);
int m=0;
int n=0;
而(m
在服务器中,您的代码等待读取1024字节,但在客户端,您仅以
strlen(msg)
的形式发送26字节,因此您的服务器将永远不会从
读取套接字返回

对于任何socket客户机-服务器应用程序,您需要为客户机和服务器定义自己的协议,以确定何时读取了所有数据,方法是确定固定长度的数据包,或者将数据长度作为数据本身的一部分

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

现在我想知道是否有可能保持插座打开 用于进一步的数据传输

是的,绝对如此——一般来说,您可以随时打开套接字,并且可以发送(和/或接收)任意多的数据

不过,在大多数情况下,接收方需要某种方法来明确解析传入数据——特别是它需要某种方法来知道一条语义“消息”(*)何时结束,下一条消息何时开始。如果只发送一条“消息”,然后关闭TCP连接,则可以避免此问题,因为EOF本身充当消息结束指示器,但如果要为多条消息保持连接打开,则需要某种方法让接收方确定消息边界所在的位置

这些信息需要在数据本身中进行编码,因为TCP协议没有承诺在每次调用recv()时将向接收进程发送多少字节;它只保证字节的接收顺序与发送顺序相同

对消息边界信息进行编码的常用方法包括:

  • 用一个短的固定大小的报头预先结束消息,该报头指示消息正文中预期的字节数
  • 指定特殊的“消息结束”字符,如