【问题标题】:Sending files between computers with C++使用 C++ 在计算机之间发送文件
【发布时间】:2012-06-29 04:14:50
【问题描述】:

我正在尝试编写一个程序,该程序使用 C++ 通过 Internet(或 LAN)将基本文本文件从一台计算机发送到另一台计算机。我正在研究 Winsock,但我读到的所有内容都让它看起来只是用于服务器和客户端之间的通信。我不确定这是否是我想要做的,或者我是否正在寻找一个不同的问题。

编辑:感谢您的出色回答。我有点为不得不从很多中选择一个最好的而感到难过。

【问题讨论】:

  • P2P library for C++ 的可能重复项
  • 我认为您的概念性问题来自作为接口的套接字,您需要在接口之上使用协议。
  • 这个程序已经存在。看ftpscp
  • 一定要用sockets吗?为什么不在一台计算机上进行共享并将文件复制到该计算机上呢?记住,不要让它变得比它需要的更复杂。 :)

标签: c++ file network-programming winsock


【解决方案1】:

这是一个如何在 Linux 中使用 C/C++ 复制/传输文件的示例。server 侦听端口 8080。client 传输文件名。 server 接收文件名,打开文件并将其内容发送给客户端。出于说明目的,我故意使用奇数或小缓冲区大小。

server.c 文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>

int main (int argc,char *argv[])
{
    struct sockaddr_in p;
    struct sockaddr_in q;
    int z,s,t,x,n,b = sizeof(q);
    char buf[23];
    int fd;

    s = socket(AF_INET,SOCK_STREAM,0);

    bzero (&p,sizeof(p));
    p.sin_family = AF_INET;
    p.sin_addr.s_addr = INADDR_ANY;
    p.sin_port = htons(8080);

    bind (s,(struct sockaddr*)&p,sizeof(p));
    listen(s,13);

    while (1) {
        t = accept (s,(struct sockaddr*)&q, &b);
        n = read(t,buf,23);
        buf[n] = 0;
        printf("%s sent: ",buf);
        fd = open (buf,O_RDONLY);
        z = lseek(fd,0,SEEK_END);
        lseek(fd,0,SEEK_SET);
        x = 0;
        do {
            n = read (fd,buf,23);
            write (t,buf,n);
            x += n;
        } while (x < z);
        printf("%d/%d\n",x,z);
        close(fd);
        close(t);
    }
}

client.c 文件:

#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>

void main (int argc, char *argv[]) 
{
    int ret;
    char buf[5];
    int s,n,fd;
    struct sockaddr_in p;
    struct hostent *h;
    char *str = argv[1];

    fd = open (str,O_CREAT | O_WRONLY,S_IRUSR|S_IWUSR);
    h = gethostbyname("127.0.0.1");

    bzero(&p,sizeof(p));
    p.sin_family = AF_INET;
    p.sin_addr.s_addr = htonl(INADDR_ANY);
    p.sin_addr.s_addr = ((struct in_addr*)(h->h_addr))->s_addr;
    p.sin_port = htons(8080);

    s = socket (AF_INET,SOCK_STREAM,0);
    connect (s,(void*)&p,sizeof(p));
    n = write (s,str,strlen(str));
    int idx = 0;
    do {
        n = read (s,buf,5);
        idx += n;
        printf(".");
        fflush(stdout);
        write (fd,buf,n);
    } while (n > 0);
    close (fd);
    close (s);
}

编译:

  1. 打开终端
  2. gcc -o server server.c
  3. gcc -o client client.c

./server 运行服务器。然后复制rngoidiot.txt,以./client rngoidiot.txt 运行客户端,文件将使用TCP/IP 复制。简单组合;-)

【讨论】:

    【解决方案2】:

    简而言之:是的,套接字是要走的路。

    套接字意义上的“服务器”和“客户端”是通用术语——您的系统在任何给定时间都在运行这两者。例如,您的 Web 浏览器作为 HTTP 客户端运行(其中 HTTP 是在 TCP/IP 上运行的文本绑定的大部分同步协议); Windows 文件共享和远程桌面是其他系统连接的“服务器”。

    在套接字意义上(实际上是在 TCP/IP 意义上)服务器和客户端之间的区别在于“服务器”套接字侦听来自远程系统的传入连接(请参阅 MSDN 或有关 bind() 的手册页,listen( ), accept()) 而“客户端”套接字创建到远程系统的传出连接 (connect())。

    请注意,套接字编程可能有点棘手。您所描述的是一个很好的学习练习,但如果您想快速完成某件事,您可能会查看现有的工具,例如 netcat。

    【讨论】:

      【解决方案3】:

      客户端-服务器架构应该适合发送文件。 “服务器”只是首先启动的程序,并等待另一个(客户端)连接到它。过去,两者之间没有太大区别。在很多情况下,编写代码是最容易的,它会自动尝试联系服务器,如果找不到,它会将自己设置为服务器。

      另请注意,使用(特别是)涉及 NAT 路由器的互联网上的工作可能会使代码有点棘手。如果您预先配置防火墙以允许连接,这并不是那么困难,但否则您通常最终会使用 UPnP 通过防火墙建立连接。与不涉及 NAT 的本地工作相比,这很容易使工作翻倍。

      【讨论】:

        【解决方案4】:

        好像只用于服务器和客户端之间的通信

        那又怎样?将一台计算机(即将接收文件)作为服务器。在该计算机上创建一个套接字并使其侦听端口上的连接。一旦连接到达,根据一些定义的结构获取数据(见下文)

        发送方计算机(客户端)将连接到另一台计算机,它知道 IP 地址和端口号。 (客户端必须知道这两者才能进行连接)。一旦建立连接,它将以字节序列的形式将数据发送到服务器。

        结构

        在此处进行通信的两台计算机必须具有明确定义的结构,并且双方都知道并接受。最简单的结构是:

        |Length-Of-Data | Data ......  |
         <-- 4 bytes---> <-- n bytes-->
        

        从前 4 个字节读取 n。这里的 4 字节 (n) 表示数据的长度,可能会有所不同,这是您的定义。

        对于文件名、文件类型等,您可以拥有更多“字段”(取决于功能)。

        【讨论】:

          【解决方案5】:

          如果你想通过互联网发送文件,你必须使用套接字,或者更好的其他用套接字实现的高级库。

          在 TCP 套接字术语中,客户端和服务器之间没有太大区别:通信是两种方式。唯一的区别在于谁在侦听传入连接(绑定、侦听、接受),以及谁在启动连接(打开)。

          你提到了 Winsock,这意味着你在 Windows 上工作。看看 Windows API,你可能会找到一些处理文件传输的高级库(如 FTP 或 HTTP 库)。

          也许不符合您的要求,但您也可以将共享文件夹用于 LAN,并使用 Dropbox 同步的文件夹用于 Internet...然后只需使用标准 IO。

          【讨论】:

            【解决方案6】:

            一般来说,任何文件传输都需要某种服务器/客户端连接。一台计算机需要发起连接,另一台计算机需要在另一端侦听连接,然后执行第一台计算机指示的操作。

            虽然您当然可以使用套接字推出自己的客户端和服务器软件,但这取决于您想要在哪种计算机之间传输文件,利用一些现有的客户端/服务器协议可能是最有意义的。一些更流行的可能性包括 ssh、http 或 ftp。我认为所有这些协议都应该存在 C/C++ 库。

            如果没有更多信息,我会倾向于使用 ssh。安装一个 ssh 服务器应该不会太难,所以你只需要编写客户端软件,我认为有一些相当不错的开源库。

            编辑:libssh 看起来不错!

            【讨论】: