C使用TCP协议进行文件传输TOC
实现方法
1.服务端程序创建一个 TCP 服务器套接字,并且绑定到特定的 IP 地址和端口上,开始监听客户端的连接请求。
2.客户端程序创建一个 TCP 客户端套接字,并且连接到服务器的 IP 地址和端口。
3.客户端向服务端发送待传输的文件名,服务端接收到文件名后,判断文件是否存在,如果存在则回复客户端,并发送文件大小给客户端。
4.客户端接收到服务端回复,并获取到文件大小后,开始发送文件数据。客户端可以通过循环读取文件数据,并且调用 send() 函数将数据发送给服务端。
5.服务端接收到客户端发送的数据后,将数据写入文件中。服务端可以通过循环接收数据,并且调用 write() 函数将数据写入文件。
6.当客户端发送完所有数据后,关闭套接字,并且通知服务端文件传输已经完成。服务端接收到客户端发送的数据后,关闭套接字。
注意
1.在文件传输过程中需要考虑数据的完整性和准确性,可以通过计算校验和或使用哈希算法来校验传输数据的正确性。
2.当传输的文件较大时,需要分批进行传输,可以通过分块传输的方式进行。
3.在传输数据之前,需要将数据进行封装,添加一些元信息,用于传输控制和数据校验。
4.在编写程序时需要考虑网络延迟、丢包等问题,采用合适的方式进行重传或者补偿。
5.在传输文件时需要考虑数据安全性以及传输过程中的加密和解密等问题。
直接上代码
服务端程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 8888
int main()
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
// 创建 TCP 服务器套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置套接字选项,允许重用地址和端口
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
// 设置地址和端口
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定套接字到特定地址和端口
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
// 开始监听客户端连接请求
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
printf("Waiting for connections...\n");
// 等待客户端连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t *)&addrlen)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
printf("Connection accepted.\n");
// 接收客户端发送的文件名
char filename[1024];
valread = read(new_socket, filename, 1024);
if (valread < 0)
{
perror("read");
exit(EXIT_FAILURE);
}
printf("Received filename: %s\n", filename);
// 打开文件并获取文件大小
FILE *fp;
if ((fp = fopen(filename, "rb")) == NULL)
{
perror("fopen");
exit(EXIT_FAILURE);
}
fseek(fp, 0, SEEK_END);
int file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
// 回复客户端并发送文件大小
char filesize_str[32];
sprintf(filesize_str, "%d", file_size);
valread = send(new_socket, filesize_str, strlen(filesize_str), 0);
if (valread < 0)
{
perror("send");
exit(EXIT_FAILURE);
}
// 发送文件数据
char buffer[1024];
int bytes_read;
while ((bytes_read = fread(buffer, 1, 1024, fp)) > 0)
{
if (send(new_socket, buffer, bytes_read, 0) != bytes_read)
{
perror("send");
exit(EXIT_FAILURE);
}
}
fclose(fp);
close(new_socket);
close(server_fd);
printf("File transfer completed.\n");
return 0;
}
客户端程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 8888
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char buffer[1024] = {0};
// 创建 TCP 客户端套接字
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 将 IP 地址从点分十进制转换为二进制形式
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
// 连接到服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
// 发送文件名
char *filename = "test.jpg";
valread = send(sock, filename, strlen(filename), 0);
if (valread < 0)
{
perror("send");
return -1;
}
// 接收文件大小
char filesize_str[32];
valread = read(sock, filesize_str, 32);
if (valread < 0)
{
perror("read");
return -1;
}
int file_size = atoi(filesize_str);
// 接收文件数据
FILE *fp;
if ((fp = fopen("recv.jpg", "wb")) == NULL)
{
perror("fopen");
return -1;
}
int bytes_received = 0;
int bytes_left = file_size;
while (bytes_left > 0)
{
int bytes_to_receive = bytes_left < 1024 ? bytes_left : 1024;
bytes_received = read(sock, buffer, bytes_to_receive);
if (bytes_received < 0)
{
perror("read");
return -1;
}
fwrite(buffer, 1, bytes_received, fp);
bytes_left -= bytes_received;
}
fclose(fp);
close(sock);
printf("File transfer completed.\n");
return 0;
}