C语言使用TCP协议传输文件

一、 C语言使用TCP协议通过windows客户端给Linux服务端发送文本文件

1. 大概步骤

  1. windows客户端中创建一个文本文件·file.txt`。
  2. windows客户端读取本地文件所有内容发送给服务端。
  3. 服务端接收消息并在服务器上创建文件写入所有内容。

2. 编写客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

#define SERVER_IP "10.0.3.1" // 替换为Linux服务器IP地址
#define SERVER_PORT 9527

int main() {
WSADATA wsaData;
SOCKET sockfd;
struct sockaddr_in serverAddr;
char buffer[1024];
FILE* file;

// 初始化Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Winsock初始化失败。\n");
return 1;
}

// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET) {
printf("创建套接字失败。\n");
WSACleanup();
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &serverAddr.sin_addr);

// 连接到服务器
if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
printf("连接到服务器失败。\n");
closesocket(sockfd);
WSACleanup();
return 1;
}

// 打开文件
file = fopen("file.txt", "rb");
if (file == NULL) {
printf("无法打开文件。\n");
closesocket(sockfd);
WSACleanup();
return 1;
}

// 读取文件并发送数据
while (!feof(file)) {
size_t bytesRead = fread(buffer, 1, sizeof(buffer), file);
if (bytesRead > 0) {
send(sockfd, buffer, bytesRead, 0);
}
}

printf("文件发送成功。\n");

// 关闭文件和套接字
fclose(file);
closesocket(sockfd);
WSACleanup();
system("pause");
return 0;
}

3.编写服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define SERVER_PORT 9527

int main() {
int server_fd, client_fd;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientAddrLen = sizeof(clientAddr);
char buffer[1024];
FILE *file;

// 创建套接字
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("创建套接字失败");
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;

// 绑定套接字
if (bind(server_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
perror("绑定套接字失败");
close(server_fd);
return 1;
}

// 监听连接
if (listen(server_fd, 5) < 0) {
perror("监听连接失败");
close(server_fd);
return 1;
}

printf("等待客户端连接...\n");

// 接受客户端连接
client_fd = accept(server_fd, (struct sockaddr *)&clientAddr, &clientAddrLen);
if (client_fd < 0) {
perror("接受客户端连接失败");
close(server_fd);
return 1;
}

// 打开文件
file = fopen("received_file.txt", "wb");
if (file == NULL) {
perror("无法创建文件");
close(client_fd);
close(server_fd);
return 1;
}

// 接收数据并写入文件
ssize_t bytesRead;
while ((bytesRead = recv(client_fd, buffer, sizeof(buffer), 0)) > 0) {
fwrite(buffer, 1, bytesRead, file);
}

printf("文件接收成功。\n");

// 关闭文件和套接字
fclose(file);
close(client_fd);
close(server_fd);

return 0;
}

4.运行测试

  1. 编译运行服务端程序crawlers
  2. 编译运行客户端 程序crawlerc.exe
  3. 在服务器中查看发送文件成功。

二、TCP客户端按字节发送给服务端直到发送完毕。

1. 大概步骤

  1. windows客户端中创建一个文本文件·file.txt`。
  2. windows客户端按字节读取本地文件内容并持续发送给服务端。
  3. 服务端按字节持续接收消息并在服务器上创建文件依次写入所有内容。

2. 编写客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

#define SERVER_IP "10.0.3.1" // 替换为Linux服务器IP地址
#define SERVER_PORT 9527

int main() {
WSADATA wsaData;
SOCKET sockfd;
struct sockaddr_in serverAddr;
char buffer[1]; // 每次读取一个字节
FILE* file;

// 初始化Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Winsock初始化失败。\n");
return 1;
}

// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET) {
printf("创建套接字失败。\n");
WSACleanup();
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &serverAddr.sin_addr);

// 连接到服务器
if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
printf("连接到服务器失败。\n");
closesocket(sockfd);
WSACleanup();
return 1;
}

// 打开文件
file = fopen("file.txt", "rb");
if (file == NULL) {
printf("无法打开文件。\n");
closesocket(sockfd);
WSACleanup();
return 1;
}

// 读取文件并按字节发送数据
while (fread(buffer, 1, 1, file) > 0) {
send(sockfd, buffer, 1, 0);
}

printf("文件发送成功。\n");

// 关闭文件和套接字
fclose(file);
closesocket(sockfd);
WSACleanup();
system("pause");
return 0;
}

3.编写服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define SERVER_PORT 9527

int main() {
int server_fd, client_fd;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientAddrLen = sizeof(clientAddr);
char buffer[1]; // 每次读取一个字节
FILE *file;

// 创建套接字
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("创建套接字失败");
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;

// 绑定套接字
if (bind(server_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
perror("绑定套接字失败");
close(server_fd);
return 1;
}

// 监听连接
if (listen(server_fd, 5) < 0) {
perror("监听连接失败");
close(server_fd);
return 1;
}

printf("等待客户端连接...\n");

// 接受客户端连接
client_fd = accept(server_fd, (struct sockaddr *)&clientAddr, &clientAddrLen);
if (client_fd < 0) {
perror("接受客户端连接失败");
close(server_fd);
return 1;
}

// 打开文件
file = fopen("received_file.txt", "wb");
if (file == NULL) {
perror("无法创建文件");
close(client_fd);
close(server_fd);
return 1;
}

// 接收数据并按字节写入文件
ssize_t bytesRead;
while ((bytesRead = recv(client_fd, buffer, 1, 0)) > 0) {
fwrite(buffer, 1, bytesRead, file);
}

printf("文件接收成功。\n");

// 关闭文件和套接字
fclose(file);
close(client_fd);
close(server_fd);

return 0;
}

4.运行测试

  1. 编译运行服务端程序crawlers
  2. 编译运行客户端 程序crawlerc.exe
  3. 在服务器中查看发送文件成功。

三、TCP客户端按块发送给服务端直到发送完毕。

1. 大概步骤

  1. windows客户端中创建一个文本文件·file.txt`。
  2. windows客户端按块读取本地文件内容并持续发送给服务端。
  3. 服务端按块持续接收消息并在服务器上创建文件依次写入所有内容。

2. 编写客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

#define SERVER_IP "10.0.3.1" // 替换为Linux服务器IP地址
#define SERVER_PORT 9527
#define BUFFER_SIZE 1024

int main() {
WSADATA wsaData;
SOCKET sockfd;
struct sockaddr_in serverAddr;
char buffer[BUFFER_SIZE];
FILE* file;

// 初始化Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Winsock初始化失败。\n");
return 1;
}

// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET) {
printf("创建套接字失败。\n");
WSACleanup();
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &serverAddr.sin_addr);

// 连接到服务器
if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
printf("连接到服务器失败。\n");
closesocket(sockfd);
WSACleanup();
return 1;
}

// 打开文件
file = fopen("file.txt", "rb");
if (file == NULL) {
printf("无法打开文件。\n");
closesocket(sockfd);
WSACleanup();
return 1;
}

// 读取文件并按块发送数据
while (!feof(file)) {
size_t bytesRead = fread(buffer, 1, BUFFER_SIZE, file);
if (bytesRead > 0) {
send(sockfd, buffer, bytesRead, 0);
}
}

printf("文件发送成功。\n");

// 关闭文件和套接字
fclose(file);
closesocket(sockfd);
WSACleanup();
system("pause");
return 0;
}

3. 编写服务端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#define SERVER_PORT 9527
#define BUFFER_SIZE 1024

int main() {
int server_fd, client_fd;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientAddrLen = sizeof(clientAddr);
char buffer[BUFFER_SIZE];
FILE *file;

// 创建套接字
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("创建套接字失败");
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
serverAddr.sin_addr.s_addr = INADDR_ANY;

// 绑定套接字
if (bind(server_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
perror("绑定套接字失败");
close(server_fd);
return 1;
}

// 监听连接
if (listen(server_fd, 5) < 0) {
perror("监听连接失败");
close(server_fd);
return 1;
}

printf("等待客户端连接...\n");

// 接受客户端连接
client_fd = accept(server_fd, (struct sockaddr *)&clientAddr, &clientAddrLen);
if (client_fd < 0) {
perror("接受客户端连接失败");
close(server_fd);
return 1;
}

// 打开文件
file = fopen("received_file.txt", "wb");
if (file == NULL) {
perror("无法创建文件");
close(client_fd);
close(server_fd);
return 1;
}

// 接收数据并按块写入文件
ssize_t bytesRead;
while ((bytesRead = recv(client_fd, buffer, BUFFER_SIZE, 0)) > 0) {
fwrite(buffer, 1, bytesRead, file);
}

printf("文件接收成功。\n");

// 关闭文件和套接字
fclose(file);
close(client_fd);
close(server_fd);

return 0;
}

4.运行测试

  1. 编译运行服务端程序crawlers
  2. 编译运行客户端 程序crawlerc.exe
  3. 在服务器中查看发送文件成功。

四、TCP客户端给服务端发送文件夹。

1. 大概步骤

  1. 在 Windows 客户端中创建一个文件夹 files,并在其中放置多个文件。
  2. Windows 客户端读取文件夹名称,并通过 TCP 发送给服务端。
  3. 服务端接收名称后创建相同名称的文件夹。
  4. 客户端准备遍历读取files里面的文件。
  5. 客户端将读取到文件名发送给服务端。
  6. 服务端接收消息创建相同名称的文件。
  7. 客户端按块读取第一个打开的文件内容,并按块发送给服务端直到完成。
  8. 服务端按块接收消息,在服务器上写入第一个文件的数据直到完成。
  9. 客户端再打开下一个文件并发送文件名与文件数据,服务端再创建与接收并写入下一个文件,直到所有文件接收完毕。
  10. 注意windows与linux路径符号不同的问题

2. 编写客户端代码(Windows)

以下是 Windows 客户端代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdint.h>

#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996)

#define SERVER_IP "10.0.3.1" // 替换为Linux服务器IP地址
#define SERVER_PORT 9527
#define BUFFER_SIZE 1024

void send_all(SOCKET sock, const char* buf, int len) {
int sent = 0;
while (sent < len) {
int res = send(sock, buf + sent, len - sent, 0);
if (res <= 0) {
fprintf(stderr, "Send error: %d\n", WSAGetLastError());
exit(1);
}
sent += res;
}
}

void send_file(SOCKET sock, const char* path, const char* name) {
FILE* file = fopen(path, "rb");
if (!file) {
perror("File open failed");
return;
}

fseek(file, 0, SEEK_END);
uint64_t size = ftell(file);
fseek(file, 0, SEEK_SET);

// 发送文件名长度和文件名
uint32_t name_len = strlen(name);
uint32_t net_len = htonl(name_len);
send_all(sock, (char*)&net_len, 4);
send_all(sock, name, name_len);

// 发送文件大小
uint64_t net_size = htonll(size);
send_all(sock, (char*)&net_size, 8);

// 发送文件内容
char buffer[BUFFER_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
send_all(sock, buffer, bytes_read);
}

fclose(file);
}

void send_directory(SOCKET sock, const char* directory) {
char search_path[MAX_PATH];
snprintf(search_path, MAX_PATH, "%s\\*", directory);

WIN32_FIND_DATA find_data;
HANDLE hFind = FindFirstFile(search_path, &find_data);
if (hFind == INVALID_HANDLE_VALUE) {
perror("FindFirstFile failed");
return;
}

do {
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
if (strcmp(find_data.cFileName, ".") == 0 || strcmp(find_data.cFileName, "..") == 0) continue;

char filepath[MAX_PATH];
snprintf(filepath, MAX_PATH, "%s\\%s", directory, find_data.cFileName);

// 转换文件名分隔符
char linux_name[MAX_PATH];
strcpy(linux_name, find_data.cFileName);
for (char* p = linux_name; *p; ++p) {
if (*p == '\\') *p = '/';
}

send_file(sock, filepath, linux_name);
} while (FindNextFile(hFind, &find_data));

FindClose(hFind);
}

int main() {
WSADATA wsaData;
SOCKET sockfd;
struct sockaddr_in serverAddr;

// 初始化Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Winsock初始化失败。\n");
return 1;
}

// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET) {
printf("创建套接字失败。\n");
WSACleanup();
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &serverAddr.sin_addr);

// 连接到服务器
if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
fprintf(stderr, "Connect failed: %d\n", WSAGetLastError());
closesocket(sockfd);
WSACleanup();
return 1;
}

// 发送文件夹名称
const char* folder = "files";
uint32_t folder_len = strlen(folder) + 1;
uint32_t net_folder_len = htonl(folder_len);
send_all(sockfd, (char*)&net_folder_len, 4);
send_all(sockfd, folder, folder_len);

// 发送文件夹内容
send_directory(sockfd, folder);

printf("文件夹发送成功。\n");

// 关闭套接字
closesocket(sockfd);
WSACleanup();

return 0;
}

修改客户端代码,支持宽字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdint.h>
#include <locale.h>

#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996)

#define SERVER_IP "10.0.3.1" // 替换为Linux服务器IP地址
#define SERVER_PORT 9527
#define BUFFER_SIZE 1024

void send_all(SOCKET sock, const char* buf, int len) {
int sent = 0;
while (sent < len) {
int res = send(sock, buf + sent, len - sent, 0);
if (res <= 0) {
fprintf(stderr, "Send error: %d\n", WSAGetLastError());
exit(1);
}
sent += res;
}
}

void send_file(SOCKET sock, const wchar_t* path, const char* name) {
FILE* file = _wfopen(path, L"rb");
if (!file) {
perror("File open failed");
return;
}

fseek(file, 0, SEEK_END);
uint64_t size = _ftelli64(file);
fseek(file, 0, SEEK_SET);

// 发送文件名长度和文件名
uint32_t name_len = strlen(name);
uint32_t net_len = htonl(name_len);
send_all(sock, (char*)&net_len, 4);
send_all(sock, name, name_len);

// 发送文件大小
uint64_t net_size = htonll(size);
send_all(sock, (char*)&net_size, 8);

// 发送文件内容
char buffer[BUFFER_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
send_all(sock, buffer, bytes_read);
}

fclose(file);
}

void send_directory(SOCKET sock, const wchar_t* directory) {
wchar_t search_path[MAX_PATH];
_snwprintf(search_path, MAX_PATH, L"%s\\*", directory);

WIN32_FIND_DATAW find_data;
HANDLE hFind = FindFirstFileW(search_path, &find_data);
if (hFind == INVALID_HANDLE_VALUE) {
perror("FindFirstFile failed");
return;
}

do {
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
if (wcscmp(find_data.cFileName, L".") == 0 || wcscmp(find_data.cFileName, L"..") == 0) continue;

wchar_t filepath[MAX_PATH];
_snwprintf(filepath, MAX_PATH, L"%s\\%s", directory, find_data.cFileName);

// 转换文件名分隔符并转换为多字节字符
char linux_name[MAX_PATH];
WideCharToMultiByte(CP_UTF8, 0, find_data.cFileName, -1, linux_name, MAX_PATH, NULL, NULL);
for (char* p = linux_name; *p; ++p) {
if (*p == '\\') *p = '/';
}

send_file(sock, filepath, linux_name);
} while (FindNextFileW(hFind, &find_data));

FindClose(hFind);
}

int main() {
setlocale(LC_ALL, "");

WSADATA wsaData;
SOCKET sockfd;
struct sockaddr_in serverAddr;

// 初始化Winsock
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Winsock初始化失败。\n");
return 1;
}

// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == INVALID_SOCKET) {
printf("创建套接字失败。\n");
WSACleanup();
return 1;
}

// 设置服务器地址和端口
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &serverAddr.sin_addr);

// 连接到服务器
if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
fprintf(stderr, "Connect failed: %d\n", WSAGetLastError());
closesocket(sockfd);
WSACleanup();
return 1;
}

// 发送文件夹名称
const wchar_t* folder = L"files";
char folder_mb[MAX_PATH];
WideCharToMultiByte(CP_UTF8, 0, folder, -1, folder_mb, MAX_PATH, NULL, NULL);

uint32_t folder_len = strlen(folder_mb) + 1;
uint32_t net_folder_len = htonl(folder_len);
send_all(sockfd, (char*)&net_folder_len, 4);
send_all(sockfd, folder_mb, folder_len);

// 发送文件夹内容
send_directory(sockfd, folder);

printf("文件夹发送成功。\n");

// 关闭套接字
closesocket(sockfd);
WSACleanup();

return 0;
}

3. 编写服务端代码(Linux)

以下是 Linux 服务端代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <stdint.h>

#define SERVER_PORT 9527
#define BUFFER_SIZE 1024

uint64_t ntohll(uint64_t val) {
return ((uint64_t)ntohl(val & 0xFFFFFFFF) << 32) | ntohl(val >> 32);
}

void recv_all(int sock, char *buf, int len) {
int received = 0;
while (received < len) {
int res = recv(sock, buf + received, len - received, 0);
if (res <= 0) {
perror("Receive error");
exit(1);
}
received += res;
}
}

int main() {
int serv_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(SERVER_PORT),
.sin_addr.s_addr = INADDR_ANY
};

int optval = 1;
// 设置 SO_REUSEADDR
if (setsockopt(serv_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
perror("setsockopt SO_REUSEADDR failed");
}

if (bind(serv_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("Bind failed");
close(serv_fd);
return 1;
}

if (listen(serv_fd, 5) < 0) {
perror("Listen failed");
close(serv_fd);
return 1;
}

printf("Server listening on port %d...\n", SERVER_PORT);

int client_fd = accept(serv_fd, NULL, NULL);
if (client_fd < 0) {
perror("Accept failed");
close(serv_fd);
return 1;
}

// 接收文件夹名称
uint32_t folder_len;
recv_all(client_fd, (char *)&folder_len, 4);
folder_len = ntohl(folder_len);

char folder[BUFFER_SIZE];
recv_all(client_fd, folder, folder_len);
mkdir(folder, 0755);

while (1) {
// 接收文件名长度
uint32_t name_len;
if (recv(client_fd, (char *)&name_len, 4, 0) <= 0) break;
name_len = ntohl(name_len);
if (name_len == 0) break;

// 接收文件名
char filename[BUFFER_SIZE];
recv_all(client_fd, filename, name_len);
filename[name_len] = 0;

// 接收文件大小
uint64_t file_size;
recv_all(client_fd, (char *)&file_size, 8);
file_size = ntohll(file_size);

// 创建文件路径
char path[BUFFER_SIZE];
snprintf(path, sizeof(path), "%s/%s", folder, filename);

// 创建必要目录
char *p = strchr(path, '/');
while ((p = strchr(p + 1, '/'))) {
*p = 0;
mkdir(path, 0755);
*p = '/';
}

FILE *file = fopen(path, "wb");
if (!file) {
perror("File create failed");
continue;
}

// 接收文件内容
uint64_t received = 0;
char buffer[BUFFER_SIZE];
while (received < file_size) {
int to_read = file_size - received > BUFFER_SIZE ? BUFFER_SIZE : file_size - received;
recv_all(client_fd, buffer, to_read);
fwrite(buffer, 1, to_read, file);
received += to_read;
}

fclose(file);
printf("Received: %s (%lu bytes)\n", path, file_size);
}

close(client_fd);
close(serv_fd);
return 0;
}

4. 运行测试

  1. 编译并运行服务端程序:
  2. 编译并运行客户端程序:
  3. 在服务器中查看 received_files 文件夹,确认文件夹及其所有文件已成功发送和接收。

Linux服务端给windows客户端发送文件

1.LinServer.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // For close()
#include <arpa/inet.h> // For inet_addr()
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>

#define PORT 8080
#define CHUNK_SIZE 1024

int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char *filename = "落叶的位置.mp4"; // Replace with your media file
FILE *file;
char buffer[CHUNK_SIZE];

// Create socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Socket failed");
exit(EXIT_FAILURE);
}

// Prepare the sockaddr_in structure
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY; // Accept any IP address
address.sin_port = htons(PORT);

// Bind
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("Server bound to port %d\n", PORT);

// Listen
if (listen(server_fd, 3) < 0) {
perror("Listen");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("Server listening...\n");

// Accept incoming connection
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t *)&addrlen)) < 0) {
perror("Accept");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("Connection accepted\n");

// Open file
file = fopen(filename, "rb");
if (file == NULL) {
perror("File not found");
close(new_socket);
close(server_fd);
exit(EXIT_FAILURE);
}

// Send file
size_t n;
while ((n = fread(buffer, sizeof(char), CHUNK_SIZE, file)) > 0) {
if (send(new_socket, buffer, n, 0) < 0) {
perror("Send");
fclose(file);
close(new_socket);
close(server_fd);
exit(EXIT_FAILURE);
}
}
printf("File sent successfully\n");

// Clean up
fclose(file);
close(new_socket);
close(server_fd);

return 0;
}

2.WinClient.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h> // Winsock library
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib") // Link with Winsock library
#pragma warning(disable:4996)
#define PORT 8080
#define CHUNK_SIZE 1024

int main() {
WSADATA wsa;
SOCKET sock;
struct sockaddr_in server;
char* filename = "received_media_file.mp4"; // File to save as
FILE* file;
char buffer[CHUNK_SIZE];
int bytes_received;

// Initialize Winsock
printf("Initializing Winsock...\n");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("Failed. Error Code: %d", WSAGetLastError());
return 1;
}
printf("Winsock initialized.\n");

// Create socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
printf("Could not create socket: %d", WSAGetLastError());
WSACleanup();
return 1;
}
printf("Socket created.\n");

// Prepare server address
server.sin_addr.s_addr = inet_addr("10.0.3.1"); // Replace with server IP
server.sin_family = AF_INET;
server.sin_port = htons(PORT);

// Connect to server
if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
printf("Connection failed with error code: %d", WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
}
printf("Connected to server.\n");

// Open file to write
file = fopen(filename, "wb");
if (file == NULL) {
perror("File");
closesocket(sock);
WSACleanup();
return 1;
}

// Receive file
do {
bytes_received = recv(sock, buffer, CHUNK_SIZE, 0);
if (bytes_received > 0) {
fwrite(buffer, sizeof(char), bytes_received, file);
}
else if (bytes_received == 0) {
break;
}
else {
printf("recv failed with error: %d\n", WSAGetLastError());
fclose(file);
closesocket(sock);
WSACleanup();
return 1;
}
} while (bytes_received > 0);
printf("File received successfully.\n");

// Cleanup
fclose(file);
closesocket(sock);
WSACleanup();

return 0;
}