1、基于 Socket 和 JSON 的服务器与客户端文件传输

本文介绍了如何使用Socket和JSON在Linux环境下实现服务器与客户端之间的文件传输,支持多客户端并发连接。通过JSON格式命令进行操作,如查询文件列表、传输指定文件,特别适用于特定项目需求。服务器端核心代码包括创建非阻塞Socket、监听客户端连接及线程处理。客户端基于Qt编写,可在Windows和Ubuntu上运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


   近期由于项目需要, 在 linux 下写了一个服务器与客户端之间进行文件的传输, 可以同时监听多个客户端, 与多个客户端进行传输。基本需求如下 :

1、服务端监听客户端, 当监听到客户端连接时,创建一个线程去完成后续处理工作从而实现同时连接多个客户端。

2、命令与数据分开传递,其中命令采用JSON格式。客户端可以通过命令查询指定目录的文件链表,可以指定需要传    输的文件, 当收到的是图片文件时,通过界面显示。


由于项目的特殊性, 这里只能列出部分功能


传输中定义的 Json 的格式如下 :


/* ----------------- 下发的消息 ----------------- */
获取文件链表
{
    "MsgType": "Cmd",
    "MsgID"  : 0x0D,
}

同步指定文件
{
    "MsgType"  : "Cmd",
    "MsgID"    :  0x0E,
    "FileName" : "/tmp/SD0/DCIM/140101100/001836AB.MP4"
}

/* ----------------- 接收的消息 ----------------- */
连接成功 
{
    "MsgType"      : "ConnectInfo"
    "CmdInfoArray" : [
                        {
                            "MsgValue" : "Success"
                        }
                     ]
}

即将同步的文件信息
{
    "MsgType"      : "FileInfo",
    "CmdInfoArray" : [

                         {                    
                             "FileName" : "/tmp/SD0/DCIM/140101100/00013100.JPG",
     "FileSize" : 1457969
                         } 

                      ]

}

获取文件列表
{
    "MsgType"      : "FileListInfo"
    "CmdInfoArray" : [ 

                        {
                            "FileName" : "/tmp/SD0/DCIM/140101100/00013100.JPG",
                            "FileSize" : 1457969
                        }, 

                        {
                            "FileName" : "/tmp/SD0/DCIM/140101100/00025500.JPG",
                            "FileSize" : 1468719
                        }, 

                        {
                            "FileName" : "/tmp/SD0/DCIM/140101100/00025501.JPG",
                            "FileSize" : 1455959
                        }, 

                        {
                            "FileName" : "/tmp/SD0/DCIM/140101100/00025600.JPG",
                            "FileSize" : 1484678
                        }, 

                        {
                            "FileName" : "/tmp/SD0/DCIM/140101100/000308AA.MP4",
                            "FileSize" : 41943040
                        }, 

                        {
                            "FileName" : "/tmp/SD0/DCIM/140101100/000308AB.MP4",
                            "FileSize" : 20971520
                        }

                    ]

}


linux Server 核心代码 :

代码可以在 linux 下运行, 也可以在 ARM-Linux 下运行, 如要在 ARM-Linux 下运行, 使用修叉编译器即可


/*  创建指定端口的 socket  */

int create_socket(const int portNum, fd_set *set_fd)
{
    int ret;

    int server_fd = -1;

    struct sockaddr_in server_addr;

    /* ---------- 创建 IPv4 的流式套接字描述符 ---------- */
    if  (-1 == (server_fd = socket(AF_INET, SOCK_STREAM, 0)))
    {
        perror("Socket Error\r\n");

        return -1;
    }

    int yes = 1;

    /* -------------- 解决 Addr Areay used -------------- */
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))) 
    {
    perror("setsockopt failed");
        
        return -1;
    }

    /* ------------------ 设置非阻塞 ------------------ */
    set_sock_NonBlock(server_fd);


    /* ---------- 填充服务器端 sockaddr 地址结构 ---------- */
    bzero(&server_addr, sizeof(struct sockaddr_in));
    server_addr.sin_family      = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port        = htons(portNum);

    ret = bind(server_fd,(struct sockaddr *)(&server_addr), sizeof(struct sockaddr));
    
    if (-1 == ret)
    {
        perror("Bind error\r\n");
         
        return -1;
    }

    if (-1 == listen(server_fd, 4))   
    {
        perror("Listen error\r\n");
         
        return -1;
    }

    FD_ZERO(set_fd);
    FD_SET(server_fd, set_fd);

    return server_fd;
}   


/* main 函数 */

int main(int argc, char *argv[])
{
    int cmd_server_fd = -1;
    int cmd_client_fd = -1;  

    int dat_server_fd = -1;
    int dat_client_fd = -1;

    fd_set cmd_set_fd;
    fd_set dat_set_fd;

    struct sockaddr_in cmd_client_addr;
    struct sockaddr_in dat_client_addr;

    socklen_t addr_len = (socklen_t)sizeof(struct sockaddr_in);

    /*---------------- 创建服务端 Socket ----------------*/
    cmd_server_fd = create_socket(CmdPortNum, &cmd_set_fd);
    dat_server_fd   = create_socket(DatPortNum,   &dat_set_fd);

    while (1)
    {
        if ( select(cmd_server_fd + 1, &cmd_set_fd, NULL, NULL, 

             (struct timeval *)0) > 0 )
        {
             if (FD_ISSET(cmd_server_fd, &cmd_set_fd) > 0)
             {
                  cmd_client_fd = accept(cmd_server_fd, 

                                        (struct sockaddr *)(&cmd_client_addr), 

                                         &addr_len);

                  if ( cmd_client_fd == -1 )
                  {
                      perror("Cmd Accept error\r\n");
                  }
                  else
                  {
                      printf("\r\nCmd  Socket Connect from %s\r\n", 

                             inet_ntoa(cmd_client_addr.sin_addr));

                      pthread_t cmd_thread_pid;

                      /* 创建新的命令线程 */
                       pthread_create(&cmd_thread_pid, NULL, (void *)cmd_deal_thread,

                                      &cmd_client_fd);
   }
      }
         }

         if ( select(dat_server_fd + 1, &dat_set_fd, NULL, NULL, 

              (struct timeval *)0) > 0 )
         {
             if ( FD_ISSET(dat_server_fd, &dat_set_fd) > 0 )
             {
                 dat_client_fd = accept(dat_server_fd, 

                                (struct sockaddr *)(&dat_client_addr), &addr_len);

                 if (-1 == dat_client_fd)
                 {
                      perror("Dat Accept error\r\n");
                 }
                 else
                 {
                      printf("Data Socket Connect from %s\r\n", 

                              inet_ntoa(dat_client_addr.sin_addr));

              pthread_t dat_thread_pid;

                      /* 创建新的数据线程 */
                      pthread_create(&dat_thread_pid, NULL, 

                                     (void *)data_trans_thread, &dat_client_fd);
                }
            }
        }
    }

    exit(0);
}


客户端用 Qt 写的,  代码在 Windows 下和 Ubuntu 下均可以使用, 

Ubuntu 下的效果 :



windows 下的效果




源代码 :

http://download.youkuaiyun.com/detail/zhou0842/9672416



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值