C语言实现Linux Socket文件传输实例

Owen
Owen
发布时间:2026-10-13| 5人浏览过
原创

本文展示如何使用C语言在Linux系统中基于TCP协议实现可靠的Socket文件传输功能。内容涵盖服务器端监听与发送逻辑,以及客户端连接、接收与保存逻辑,包含完整的错误处理机制。

原理与核心流程

基于TCP的文件传输依赖于稳定的双向字节流。其核心交互顺序为:Server负责绑定端口并等待客户端接入,获取连接后执行握手消息交换(可选)并打开本地文件进行读取;Client通过IP和端口发起连接,验证服务端响应后创建输出文件,进入循环从Socket缓冲区接收数据块并写入磁盘。

准备条件

  • 操作系统:Linux (内核版本不限,标准POSIX接口)。
  • 依赖库:需链接 libsocket 及 librt (视系统而定),通常编译命令为 gcc -o server server.c。
  • 文件权限:确保服务器对源文件有读权限,客户端对目标路径有写权限。

第1步:配置并运行服务器端 (server.c)

目的:启动后台服务,侦听指定端口并对外发送名为“data1”的文本文件。

关键参数:

  • HELLO_WORLD_SERVER_PORT: 7754 (通信端口号)。
  • BUFFER_SIZE: 1024 (每次I/O操作的缓冲区大小)。

服务端实现了标准的阻塞式TCP监听模型。首先初始化 sockaddr_in 结构体并将端口绑定至任意可用网卡接口 (INADDR_ANY)。调用 listen() 后进入无限循环调用 accept() 获取新连接。一旦连接建立,先发送一条欢迎信息,随后以二进制安全的方式读取本地文件 data1,按 BUFFER_SIZE 分片调用 send() 传输,直到文件末尾。

////////////////////////////////////
//服务器代码
///////////////////////////////////
#include <netinet/in.h>  // for sockaddr_in
#include <sys/types.h>  // for socket
#include <sys/socket.h>  // for socket
#include <stdio.h>    // for printf
#include <stdlib.h>    // for exit
#include <string.h>    // for bzero
#include <time.h>        //for time_t and time
#define HELLO_WORLD_SERVER_PORT 7754
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
int main(int argc, char **argv)
{
    //设置一个socket地址结构server_addr,代表服务器internet地址, 端口
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);

    FILE *stream;

    //创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket
    int server_socket = socket(AF_INET,SOCK_STREAM,0);
    if( server_socket < 0)
    {
        printf("Create Socket Failed!");
        exit(1);
    }

    //把socket和socket地址结构联系起来
    if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
    {
        printf("Server Bind Port : %d Failed!
"HELLO_WORLD_SERVER_PORT);
        exit(1);
    }

    //server_socket用于监听
    if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )
    {
        printf("Server Listen Failed!");
        exit(1);
    }

    while (1) //服务器端要一直运行
    {
        struct sockaddr_in client_addr;
        socklen_t length = sizeof(client_addr);
        int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
        if ( new_server_socket < 0)
        {
            printf("Server Accept Failed!\n");
            break;
        }

        char buffer[BUFFER_SIZE];
        bzero(buffer, BUFFER_SIZE);
        strcpy(buffer,"Hello,World! 从服务器来!");
        strcat(buffer,"\n"); //C语言字符串连接
        send(new_server_socket,buffer,BUFFER_SIZE,0);

        bzero(buffer,BUFFER_SIZE);
        //接收客户端发送来的信息到buffer中
        length = recv(new_server_socket,buffer,BUFFER_SIZE,0);
        if (length < 0)
        {
            printf("Server Recieve Data Failed!\n");
            exit(1);
        }
        printf("\n%s",buffer);

        if((stream = fopen("data1","r"))==NULL)
        {
            printf("The file 'data1' was not opened! \n");
            exit(1);
        }
        else
            printf("The file 'filename' was opened! \n");

        bzero(buffer,BUFFER_SIZE);
        int lengsize = 0;
        while((lengsize = fread(buffer,1,1024,stream)) > 0)
        {
            printf("lengsize = %d\n",lengsize);
            if(send(new_server_socket,buffer,lengsize,0)<0)
            {
                printf("Send File is Failed\n");
                break;
            }
            bzero(buffer, BUFFER_SIZE);
        }
        if(fclose(stream))
            printf("The file 'data' was not closed! \n");
        exit(1);     
        //关闭与客户端的连接
        close(new_server_socket);    
    }
    //关闭监听用的socket
    close(server_socket);
    return 0;
}

第2步:启动并测试客户端 (client.c)

目的:连接到已运行的服务端,接收文件流并保存为本地 data 文件。

运行方式:需要传入服务端IP作为参数,例如 .\client 127.0.0.1 (Windows CMD) 或 ./client 127.0.0.1 (Linux Terminal)。

客户端首先检查命令行参数数量。成功创建流式Socket后,将自动分配临时端口并绑定到本机任何IP上。通过 inet_aton(argv[1]) 解析传入的服务端IP并填入 server_addr 结构体。随后发起 connect() 请求。连接成功后,先接收来自服务端的握手字符串,清空缓冲区后向服务端回传确认信号,然后立即打开文件 data 进入 while 循环,利用 recv() 持续填充缓冲区,并使用 fwrite() 将其持久化写入磁盘。

////////////////////////////////////
//客户端代码
///////////////////////////////////
#include <netinet/in.h>  // for sockaddr_in
#include <sys/types.h>  // for socket
#include <sys/socket.h>  // for socket
#include <stdio.h>    // for printf
#include <stdlib.h>    // for exit
#include <string.h>    // for bzero
#include <time.h>        //for time_t and time
#include <arpa/inet.h>
#define HELLO_WORLD_SERVER_PORT  7754
#define BUFFER_SIZE 1024
int main(int argc, char **argv)
{
    if (argc != 2)
    {
        printf("Usage: ./%s ServerIPAddress\n",argv[0]);
        exit(1);
    }

    //time_t now;
    FILE *stream;

    //设置一个socket地址结构client_addr,代表客户机internet地址, 端口
    struct sockaddr_in client_addr;
    bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
    client_addr.sin_family = AF_INET;  //internet协议族
    client_addr.sin_addr.s_addr = htons(INADDR_ANY);  //INADDR_ANY表示自动获取本机地址
    client_addr.sin_port = htons(0);  //0表示让系统自动分配一个空闲端口

    //创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
    int client_socket = socket(AF_INET,SOCK_STREAM,0);
    if( client_socket < 0)
    {
        printf("Create Socket Failed!\n");
        exit(1);
    }

    //把客户机的socket和客户机的socket地址结构联系起来
    if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))
    {
        printf("Client Bind Port Failed!\n");
        exit(1);
    }

    //设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    if(inet_aton(argv[1],&server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数
    {
        printf("Server IP Address Error!\n");
        exit(1);
    }
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    socklen_t server_addr_length = sizeof(server_addr);

    //向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
    if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0)
    {
        printf("Can Not Connect To %s!\n",argv[1]);
        exit(1);
    }

    char buffer[BUFFER_SIZE];
    bzero(buffer,BUFFER_SIZE);

    //从服务器接收数据到buffer中
    int length = recv(client_socket,buffer,BUFFER_SIZE,0);
    if(length < 0)
    {
        printf("Recieve Data From Server %s Failed!\n", argv[1]);
        exit(1);
    }
    printf("\n%s\n",buffer);

    bzero(buffer,BUFFER_SIZE);
    bzero(buffer,BUFFER_SIZE);
    strcpy(buffer,"Hello, World! From Client\n");
    //向服务器发送buffer中的数据
    send(client_socket,buffer,BUFFER_SIZE,0);

    if((stream = fopen("data","w+t"))==NULL)
    {
        printf("The file 'data' was not opened! \n");
    }
    else
        bzero(buffer,BUFFER_SIZE);

    length = 0;
    while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
    {
        if(length < 0)
        {
            printf("Recieve Data From Server %s Failed!\n", argv[1]);
            break;
        }
        int write_length = fwrite(buffer,sizeof(char),length,stream);
        if (write_length<length)
        {
            printf("File is Write Failed\n");
            break;
        }
        bzero(buffer, BUFFER_SIZE); 
    }
    printf("Recieve File From Server[%s] Finished\n", argv[1]);

    //关闭 文件
    fclose(stream);
    //关闭socket
    close(client_socket);
    return 0;
}

第3步:结果判断与排错

完成状态:当服务端控制台打印完最后一次分片大小且退出程序,同时客户端输出 Recieve File From Server[...] Finished 时,当前目录下应生成名为 data 的新文件。比对文件大小与服务端 data1 一致即为成功。

常见问题排查:

  • 端口冲突:若服务端报错 Bind Port Failed,说明 7754 端口已被占用,可通过 netstat -anp | grep 7754 查看进程并更换代码中的宏定义值。
  • 连接被拒:客户端报错 Connect Fail 通常意味着服务端未启动、防火墙拦截了 7754 端口,或输入的IP地址不匹配(注意区分IPv4和IPv6)。
  • 文件截断/乱码:由于使用了 recv() 循环判断返回值,只要磁盘空间充足且中途无网络中断,文件内容通常能保持完整。

总结

通过上述步骤,您可以快速构建一个基础的点对点文件传输通道。该方案适合小文件和局域网环境下的轻量级数据传输。以上就是C语言实现Linux Socket文件传输的详细内容,更多关于C语言Socket开发的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。