基于C的socket编程实现linux虚拟机和windows传输文件(图片)
发布日期:2021-05-15 09:23:35 浏览次数:17 分类:精选文章

本文共 3534 字,大约阅读时间需要 11 分钟。

Linux 服务端 socket 代码解读与应用实践

1.1 项目背景

本项目旨在通过 Linux 服务端 socket 实现文件传输功能,实现在客户端和服务器端之间实现数据交互。本文将详细介绍服务端的实现步骤及代码解析。

1.2 项目功能概述

服务端应当具备以下功能:

  • 监听指定端口接收客户端连接
  • 处理每次连接创建新的子进程
  • 子进程负责接收客户端文件内容
  • 将接收到的文件写入本地文件
  • суб进程结束后返回处理信息

1.3 服务端代码分析

#include 
#include
#include
#include
#include
#include
#include
#define SIZE 30 void read_child(int signo) { if (signo == SIGCHLD) { int status; pid_t pid = waitpid(-1, &status, WNOHANG); printf("移除子进程挂起状态 PID=%d\n", pid); } } int main(int argc, char* argv) { int server_sock, client_sock, r; struct sockaddr_in server_addr, client_addr; pid_t pid; struct sigaction act; socklen_t len; char buf[SIZE]; if (argc != 2) { printf("需要端口号\n"); return 1; } act.sa_handler = read_child; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (-1 == sigaction(SIGCHLD, &act, 0)) { printf("Sigaction 错误\n"); return -1; } server_sock = socket(AF_INET, SOCK_STREAM, 0); if (server_sock == -1) { printf("无法获取服务器 socket\n"); return -1; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(argv[1]); if (-1 == bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr))) { printf("绑定错误\n"); return -1; } if (-1 == listen(server_sock, 10)) { printf("监听错误\n"); return -1; } while (1) { len = sizeof client_addr; client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &len); if (-1 == client_sock) continue; pid = fork(); if (pid == -1) { close(client_sock); continue; } else if (pid == 0) { close(server_sock); memset(buf, 0, SIZE); r = read(client_sock, buf, SIZE - 1); buf[r] = '\0'; FILE* fp = fopen(buf, "wb"); if (!fp) { return 1; } printf("打开文件成功\n"); memset(buf, 0, SIZE); while ((r = read(client_sock, buf, SIZE - 1)) > 0) { fwrite(buf, 1, r, fp); } fclose(fp); printf("写入文件成功\n"); close(client_sock); printf("连接客户端 IP: %s, 端口: %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); return 0; } else { printf("新客户端连接 IP: %s, 端口: %d, 子进程 PID=%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), pid); close(client_sock); } } close(server_sock); return 0; }

1.4 Windows 客户端代码解读

#include 
#include
#include
#pragma comment(lib, "ws2_32.lib")
#define IP "虚拟机IP地址"
#define PORT 8889
char filename[] = "1.jpg";
int main() {
WORD ver = MAKEWORD(2, 2);
WSADATA dat;
WSAStartup(ver, &dat);
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in sin = {};
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.S_un.S_addr = inet_addr(IP);
int len = sizeof(sin);
int r = connect(sock, (sockaddr*)&sin, len);
if (-1 == r) {
printf("连接错误\n");
return -1;
}
send(sock, filename, strlen(filename), 0);
char buf[1024] = {0};
r = recv(sock, buf, sizeof(buf), 0);
buf[r] = '\0';
printf("接收到文件名称: %s\n", buf);
FILE* fp;
fp = fopen(filename, "rb");
if (!fp) {
return 1;
}
len = fread(buf, 1, sizeof(buf), fp);
while (len > 0) {
send(sock, buf, len, 0);
len = fread(buf, 1, sizeof(buf), fp);
}
fclose(fp);
closesocket(sock);
getchar();
return 0;
}

2 常见问题及解决方案

  • 端口号占用问题:服务器启动时使用 bind() 函数,如果端口号已占用,需切换为其他端口号。

  • 接受客户端连接超时:可通过降低 listen() 函数的参数,或使用线程池管理多个连接。

  • 读取文件问题:确保客户端发送的数据以二进制格式处理,避免文本编码转换问题。

3 总结思考

本项目通过 socket API 实现了跨平台文件传输功能,服务端部分采用了进程共享的方式处理多个客户端连接,Windows 客户端部分则依托 Winsock 库实现了文件传输功能。

上一篇:io多路复用___select
下一篇:友元函数,友元类

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年04月11日 19时32分36秒