【发布时间】:2021-05-24 05:27:15
【问题描述】:
这是我第一次进行socket编程,有一个关于send和recv的问题。我正在从服务器向客户端发送一个文件,它工作正常。但是,当我想通过更多的 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;
}
【问题讨论】:
-
您必须有一个基于 TCP 的协议,它可以安全地识别文件数据的开始和结束。结束后的数据可以被.....whatever消费。
-
注意 - 你非常接近从悬崖上掉下来:'strcpy(data,"test message");' - 滥用需要以 NUL 结尾的字符数组的库调用。我怀疑您还在为滥用 TCP 八位字节流而步履蹒跚 - 假设在一次 send() 调用中发送的多字节消息将始终导致一个 recv() 调用仅加载完整的消息。
-
您确实应该检查来自
send/recv的返回值 - 即使您仅发送 512 字节大小的块,它们也可能仅发送部分数据,从而降低可能性。您不会在本地网络上遇到此问题,但如果您不测试错误,您可能会发现自己很难跟踪问题。 -
我强烈建议您研究基于 TCP 的协议规范,了解它们如何处理此类问题。查看 IRC、HTTP、SMTP、NNTP、FTP 等协议。他们都必须处理正确使用 TCP 的所有问题。