架構概覽
- 協議:TCP(SOCK_STREAM)
- 端口:6666
- 緩衝區:1024 字節
- 流程:客戶端發送文件名 → 服務端讀取文件分塊發送 → 客戶端接收寫入文件
服務端核心代碼
#include
#include
#include
#include
#include
#define PORT 6666
#define BACKLOG 20
#define BUF_SIZE 1024
#define NAME_MAX 512
int main() {
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket < 0) { perror("socket"); exit(1); }
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr))) {
perror("bind"); exit(1);
}
if (listen(server_socket, BACKLOG)) { perror("listen"); exit(1); }
while (1) {
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &len);
if (client_socket < 0) { perror("accept"); break; }
char buffer[BUF_SIZE] = {0};
int r = recv(client_socket, buffer, BUF_SIZE, 0);
if (r <= 0) { close(client_socket); continue; }
char filename[NAME_MAX+1] = {0};
strncpy(filename, buffer, strlen(buffer) > NAME_MAX ? NAME_MAX : strlen(buffer));
FILE *fp = fopen(filename, "r");
if (!fp) { printf("File %s Not Found\n", filename); }
else {
int block_len;
while ((block_len = fread(buffer, 1, BUF_SIZE, fp)) > 0) {
if (send(client_socket, buffer, block_len, 0) < 0) { perror("send"); break; }
}
fclose(fp);
printf("File %s Transfer Finished\n", filename);
}
close(client_socket);
}
close(server_socket);
return 0;
}
客戶端核心代碼
#include
#include
#include
#include
#include
#include
#define PORT 6666
#define BUF_SIZE 1024
#define NAME_MAX 512
int main(int argc, char **argv) {
if (argc != 2) { fprintf(stderr, "Usage: %s ServerIP\n", argv[0]); exit(1); }
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) { perror("socket"); exit(1); }
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
if (inet_aton(argv[1], &server_addr.sin_addr) == 0) { fprintf(stderr, "Invalid IP\n"); exit(1); }
if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("connect"); exit(1);
}
char filename[NAME_MAX+1] = {0};
printf("Please Input File Name On Server: ");
scanf("%s", filename);
send(sock, filename, strlen(filename), 0);
FILE *fp = fopen(filename, "w");
if (!fp) { perror("fopen"); exit(1); }
char buffer[BUF_SIZE];
int len;
while ((len = recv(sock, buffer, BUF_SIZE, 0)) > 0) {
fwrite(buffer, 1, len, fp);
}
fclose(fp);
close(sock);
printf("Receive File %s Finished\n", filename);
return 0;
}
關鍵點提示
- TCP 流式傳輸,單次
send/recv 不保證一次傳完/收完,生產環境需應用層協議(長度前綴/分隔符)
- 緩衝區 1024 字節避免 IP 分片
- 服務端單線程循環,高併發需
fork/pthread/epoll
- 錯誤處理簡化,實際項目需完善