我在创建像客户端/服务器(tcp)这样的小型 ftp 时面临多个问题
客户有提示。
如何停止接收问题 .通过我的套接字从我的客户端发送数据到服务器或反之亦然。
例如,从服务器向客户端发送一些字符串。客户端如何知道何时停止读取套接字并离开 recv()
循环打印回提示
这就是我创建 transfert functions
的原因如果它是最后一次发送( CONT - DONE
),则知道何时停止预发送,它工作得很好。 (下面的代码)
然后我需要执行 ls
之类的命令在服务器上并将结果发送到客户端,所以我想到了 2 个选项。
execv()
在 char*
并使用我的转移功能。 execv()
直接在我的套接字中输出。 第二个选项更简洁,但它让我面临第一个关于如何停止
recv()
的问题。环形。奖金问题:如何复制
execv()
到一个字符串。我想使用 mmap
感谢 fd
参数,但我仍然需要提前知道大小。# define BUFFSIZE 512
# define DONE "DONE"
# define CONT "CONT"
int send_to_socket(int sock, char *msg)
{
size_t len;
int ret[2];
char buff[BUFFSIZE+1];
len = strlen(msg);
bzero(buff, BUFFSIZE+1);
strncpy(buff, msg, (len <= BUFFSIZE) ? len : BUFFSIZE);
/*strncpy(buff, msg, BUFFSIZE);*/
ret[0] = send(sock, (len <= BUFFSIZE) ? DONE : CONT, 4, 0);
ret[1] = send(sock, buff, BUFFSIZE, 0);
if (ret[0] <= 0 || ret[1] <= 0)
{
perror("send_to_socket");
return (-1);
}
// recursive call
if (len > BUFFSIZE)
return (send_to_socket(sock, msg + BUFFSIZE));
return (1);
}
char *recv_from_socket(int cs)
{
char state[5];
char buff[BUFFSIZE+1];
char *msg;
int ret[2];
msg = NULL;
while (42)
{
bzero(state, 5);
bzero(buff, BUFFSIZE+1);
ret[0] = recv(cs, state, 4, 0);
ret[1] = recv(cs, buff, BUFFSIZE, 0);
if (ret[0] <= 0 || ret[1] <= 0)
{
perror("recv_from_socket");
return (NULL);
}
// strfljoin(); concat the strings and free the left parameter
msg = (msg) ? strfljoin(msg, buff) : strdup(buff);
if (strnequ(state, DONE, 4))
break ;
}
return (msg);
}
最佳答案
您已经正确判断,要通过面向流的套接字进行无差别流以外的任何通信,您需要在通信双方之间应用某种应用层协议(protocol)。这就是你的send_to_socket()
和 recv_from_socket()
功能正在运行,尽管它们存在缺陷。*
假设您确实需要使用应用层协议(protocol),那么让子进程直接写入套接字根本不是一种选择,除非您的特定 ALP 可以容纳将整个程序输出封装为单个 block ,其中一个你正在使用不能做。
话虽如此,您至少还有一个您没有考虑过的其他选择:让父级在子级生成它时将子级的输出发送到套接字,而不是收集所有输出并仅在之后发送。这将涉及在子节点和父节点之间建立管道,并且可能是send_to_socket()
的单独版本。它从 FD 而不是从字符串中读取要发送的数据。您可能会一次累积一个中等大小的缓冲区。这种方法将是我的建议。
bonus question: how to dup execv() to a string. i thought using mmap thanks to the fd parameter, but i still need to know the size in advance.
mmap()
接受一个文件描述符参数来指定要映射的文件,但这并不意味着它只适用于任何文件描述符。它只保证与指定常规文件和共享内存对象的 FD 一起使用,您不能期望它适用于指定临时数据管道的 FD。要在内存中捕获子进程的输出,您需要像我为您的第三个选项描述的那样进行操作,但是将读取的数据存储在动态分配(并根据需要重新分配)的缓冲区中,而不是将其发送给客户端它被阅读。这可能既昂贵又困惑。*你的功能缺陷:
send()
和 recv()
可以依赖函数来准确传输请求的字节数,或者失败。 事实上,
send()
和 recv()
都可以执行部分传输。为避免丢失数据和/或不同步,您必须将这些函数的返回值与您尝试传输的字节数进行比较以检测部分传输,如果发生部分传输,您必须发出另一个调用发送数据的余额。由于同样的事情可能再次发生,您通常需要将整个事情放在一个不断调用 send()
的循环中。或 recv()
视情况而定,直到发送所有数据或发生真正的故障。考虑改为发送消息长度而不是“CONT”或“DONE”,然后发送那么多字节(但见上文)。您还可以将标志位合并到消息长度中以传达附加信息——例如,指示当前 block 是否是最后一个 block 的位。
send()
是可能的和 recv()
由于与连接及其持续可行性无关的原因而导致失败的调用。例如,它们可以被信号中断。由于如果发送方和接收方之间的通信中断,您无法重新同步通信,因此您应该确保在发生错误时终止通信,尽管这实际上不必由您的 send 和 recv 函数自己处理. 关于c - TCP 客户端/服务器 : when stop read socket,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42097108/