这是我第一次进行套接字编程,并且对发送和接收有疑问。我正在从服务器向客户端发送一个文件,它工作正常。但是,当我想通过更多的 send() 和 recv() 调用(客户端和服务器末尾的注释代码)继续我的程序时,客户端会接收此数据并将其写入 newfile.txt。
所以,我的问题是,如何从服务器调用 send() 仅从 test.txt 发送数据,然后在客户端调用 recv() 仅从 test.txt 接收数据并将其写入 newfile.txt?在此之后,我想继续我的程序,使用更多的 send() 和 recv() 调用,这些调用不会与文件传输代码混淆。
客户:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
int port = 8001;
int client_socket;
struct sockaddr_in server_addr;
int connect_status;
client_socket = socket(AF_INET, SOCK_STREAM, 0); //SOCK_STREAM for TCP
if (client_socket < 0)
{
printf("Error creating socket\n");
exit(1);
}
printf("Socket created\n");
//address for socket to connect to
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port); //8001 arbitrary port
server_addr.sin_addr.s_addr = INADDR_ANY;
//connect to address of socket
connect_status = connect(client_socket, (struct sockaddr *) &server_addr, sizeof(server_addr));
if(connect_status == -1)
{
printf("Error connecting to server\n");
exit(1);
}
printf("Connected to Server\n");
FILE* fp = fopen( "newfile.txt", "w");
char data[512];
int b;
while((b=recv(client_socket, data, 512,0))>0){
fwrite(data, 1, b, fp);
}
fclose(fp);
//recv(client_socket, data, 512,0);
//printf("client buffer: %s\n", data);
close(client_socket);
return 0;
}
服务器:#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[]){
int port = 8001;
int server_socket;
struct sockaddr_in server_addr;
int client_socket, client_addr;
int bind_status, listen_status;
server_socket = socket(AF_INET, SOCK_STREAM, 0); //SOCK_STREAM for TCP
if (server_socket < 0)
{
printf("Error creating socket\n");
exit(1);
}
printf("Socket created\n");
//address for socket to connect to
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
//bind socket to the IP and port
bind_status = bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (bind_status < 0)
{
printf("Error binding to socket\n");
exit(1);
}
printf("Socket binded\n");
//listen for client connections
listen_status = listen(server_socket, 10);
if (listen_status == -1)
{
printf("Error listening to socket\n");
exit(1);
}
printf("Listening\n");
//accept client connection
socklen_t addr_len;
addr_len = sizeof(client_socket);
client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &addr_len);
FILE *fp = fopen("test.txt", "r");
char data[512];
int b;
while((b = fread(data, 1, 512, fp))>0){
send(client_socket, data, b, 0);
}
fclose(fp);
// strcpy(data,"test message");
//printf("server buffer: %s\n", data);
//send(client_socket, data, 512, 0);
close(server_socket);
return 0;
}
最佳答案
您需要某种方式来指示服务器您已经完成了文件的发送,现在您要发送另一个东西。
虽然套接字抽象似乎向您展示了 recv 和 send 调用以某种方式同步,但这意味着您在一次调用中从客户端发送的数据发送在服务器中被接收到恰好一个接收,这是不正确的,基本上是由于套接字是如何实现的(客户端 tcp 可以决定将您的传输拆分为几个数据包,并且服务器的无人参与可以使所有这些数据包在服务器在一次调用 recve 中接收到其中的一部分之前缓冲 n 接收器和其他人在文字通话中。
唯一可以确定的是,之前发送过的字节是之前接收过的,并且两者之间没有重复或丢失的字节。但是在某些 recve 调用中接收到的字节数仅取决于连接一侧具有的缓冲数据量。
这意味着,为了告诉服务器您已完成文件并且要发送其他内容,您必须执行一些操作以使服务器能够识别数据已结束并且关于不同事物的更多数据即将到来.
这里有几种方法......您可以发送一个带内序列(一些控制序列),在另一边读取时,它将被识别为数据 block 的结尾和下一个数据 block 的开头。一些系统使用分组编码,它只是在每个 block 前面加上要跟随的字节数,而一个空分组(例如,单个数字 0,意味着要跟随 0 个字节)可以表示这个序列。另一种方法,可以是使用您知道不可能出现在数据中的特定序列(例如 \n.\m
,两个换行符,其中一个点穿插——例如,这已在 unix 的 ed 编辑器中多次使用,或者邮局协议(protocol)使用它。)并且如果这种序列恰好在文件中,只需将点加倍,以表明它不是分隔符序列。并且两端必须同意(所谓的)协议(protocol)。
其他机制也是有效的,您可以关闭连接并使用另一个套接字进行新的数据交换......例如,FTP 协议(protocol)使用这种方法,使用一个控制连接进行 FTP 命令,同时使用其他连接进行数据传输。
我没有包含代码,因为文献中有很多例子。尝试访问 Richard W. Stevens 的“Unix Network Programming”一书。这是开始学习套接字协议(protocol)以及如何处理所有这些事情的一个很好的引用。
关于C 中的客户端和服务器 send() 和 recv(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66307770/