在C语言中,在不关闭套接字的情况下,如何在写入数据后指示EOF?
我是C套接字编程新手。我了解到,通过套接字发送数据后,应该在C语言中,在不关闭套接字的情况下,如何在写入数据后指示EOF?,c,sockets,keep-alive,C,Sockets,Keep Alive,我是C套接字编程新手。我了解到,通过套接字发送数据后,应该关闭或关闭套接字描述符,这将触发发送到另一端的EOF。如果没有EOF,read/recv会一直阻塞 现在我想知道是否有可能保持套接字打开以进行进一步的数据传输。从我所读到的内容来看,这似乎是人们在建立保持活动的HTTP连接时所做的事情。但我不知道这是如何实现的 下面的代码显示了该场景,该场景在客户机的写入后卡住 #include <stdio.h> #include <string.h> #include <
关闭
或关闭
套接字描述符,这将触发发送到另一端的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()时将向接收进程发送多少字节;它只保证字节的接收顺序与发送顺序相同
对消息边界信息进行编码的常用方法包括:
用一个短的固定大小的报头预先结束消息,该报头指示消息正文中预期的字节数
指定特殊的“消息结束”字符,如