C# 应用程序如何在网络上轻松通信和传输文件?

发布于 2024-08-01 19:21:50 字数 276 浏览 4 评论 0原文

C# 应用程序如何轻松地与位于同一网络上的另一台计算机上的自身实例进行通信,并传输文件和数据?

假设网络上的计算机都有固定的本地IP地址,并且它们都知道彼此的IP。 如果 IP 未知,还有办法进行通信吗? 基于某种发现协议?

我听说 Apple 的“Bonjour”服务是一个很好的协议。 我们可以通过它从 Windows 应用程序进行通信吗? 或者你必须使用“套接字”。 我主要是在寻找可以轻松满足我的需求的库或示例代码,我不想开发自己的基于 TCP 的协议或任何硬核的协议!

How can a C# app easily communicate with an instance of itself present on another computer, which is on the same network, and transfer files and data?

Assuming the computers on the network have fixed local IP addresses, and they each know each others IPs. Would there also be a way to communicate if the IPs are unknown? based on some discovery protocol?

I heard the "Bonjour" service from Apple was a good protocol. Can we communicate via it from our Windows apps? Or do you have to use "sockets". I'm primarily looking for libraries or sample code that can fulfill my need easily, I don't want to develop my own TCP-based protocol or anything hardcore!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

墨洒年华 2024-08-08 19:21:50

您可以使用 System.Net.Sockets 类进行通信,它有一个发送文件的方法 Socket.SendFile

更新:
这是文件共享和从 C# 帮助发送文件的一个很好的例子

You can use System.Net.Sockets class to communicate and it have a method for sending file Socket.SendFile.

Update:
this is a good example for file sharing and sending file from C# help

稚然 2024-08-08 19:21:50

C# 中文件和套接字的伟大之处在于它们都作为流公开。 将大文件从一个流复制到另一个流非常简单:

byte[] data = new byte[1024];
while(true) {
int bytesRead = filestream.read(data,0,data.Length);
if (bytesRead==0) break;
netstream.write(data,0,bytesRead);
}

完成后只需关闭套接字即可。

如果您想发送元数据(文件名、大小)或不想关闭连接,则需要某种协议来处理此问题。 FTP 使用两个单独的套接字(一个用于元数据,一个用于数据;这称为带外通信)。 如果您所在的 LAN 没有防火墙,那么这是完全可以接受的。 另一方面,如果你想做互联网传输,打开一个端口是一件很困难的任务,打开两个端口更是难以忍受。 如果您不太关心性能,可以使用 base64 编码对字节进行编码,这可确保它们在特定的字节范围内。 使用 Base64,您可以用换行符或其他非字母数字字符分隔消息。 然后在第一条消息中包含文件名、大小或其他内容,然后将数据作为第二条消息发送,然后发送“这就是整个文件”消息,以便客户端知道它已完成。

消息的另一种策略是使用转义序列。 例如,获取字节流并将每个“\0”实例替换为“\0\0”。 现在使用“\0\1”来表示消息结束,这保证不会包含在您的数据消息中。 在接收端将'\0\0'解码回'\0'。 这在 C 中工作得很好,但我发现,在实践中,循环遍历每个字节可能比在 C# 中读取整个缓冲区慢。

最好的方法是采用某种自适应长度协议。 例如,以一定大小(例如 512 字节)的块发送数据。 在每个块之前,通过 System.BitConverter 发送一个表示块大小的 32 位 int。 所以消息看起来像这样(英文):

Here's 512 bytes:
[data]
Here's 512 bytes:
[data]
Here's 32 bytes:
[data]
Here's 4 bytes:
That was the whole file

这里的优点是您可以让复制/读取缓冲区为您工作(一次读取 512 个字节),这意味着您的吞吐量受到网络堆栈而不是 C# 代码的限制。 客户端读取固定长度的 32 位 int,让它知道应该用于下一个 [data] 段的缓冲区的大小。

下面是一些用于编写此类消息的代码:

        logger.logger.debug("Sending message of length " + length);
        byte[] clength = System.BitConverter.GetBytes(buffer.Length);
        plaintextStream.Write(clength,0,clength.Length);
        plaintextStream.Write(buffer,0,buffer.Length);
        plaintextStream.Flush();

下面是一些用于读取消息的代码:

               byte[] intbuf = new byte[int_32_size];
        int offset = 0;
        while (offset < int_32_size)
        {
            int read = 0;

            read = d.plaintextStream.Read(intbuf,offset,int_32_size - offset);
            offset += read;

        }
        int msg_size = System.BitConverter.ToInt32(intbuf,0);
        //allocate a new buffer to fill the message
        byte[] msg_buffer = new byte[msg_size];
        offset = 0;
        while (offset < msg_size)
        {
            int read = 0;

            read = d.plaintextStream.Read(msg_buffer,offset,msg_size - offset);
            offset += read;
        }


        return msg_buffer;

The great thing about files and sockets in C# is that they're both exposed as streams. Copying a large file from one stream to another is pretty simple:

byte[] data = new byte[1024];
while(true) {
int bytesRead = filestream.read(data,0,data.Length);
if (bytesRead==0) break;
netstream.write(data,0,bytesRead);
}

Then just close the socket when you're done.

If you want to send metadata (filenames, sizes) or don't want to close the connection, you need some sort of protocol to handle this. FTP uses two seperate sockets(one for metadata, one for data; this is called out-of-band communication). If you're on a LAN with no firewalls, that can be perfectly acceptable. On the other hand, if you want to do internet transfer, getting a single port open is a difficult-enough task, and two is unbearable. If you don't care too much about performance, you could encode the bytes in base64 encoding, which makes sure that they're within a certain byte range. With base64, you can seperate messages with newlines or other non-alphanumeric characters. Then in the first message include the filename, size, or whatever, then send the data as a second message, then send a "that's the whole file" message so the client knows it's done.

Another tactic for messages is using an escape sequence. For instance, take your bytestream and replace each instance of '\0' with '\0\0'. Now use '\0\1' to signal the end-of-message, which is guaranteed not to be contained in your data message. Decode the '\0\0' back to '\0' on the receiving end. This works well enough in C, but I find that, in practice, looping through each byte can be slower than reading whole buffers in C#.

The best way is to adopt some sort of adaptive-length protocol. For instance, send the data in chunks of a certain size (say 512 bytes). Before each chunk, send a 32bit int representing the size of the chunk via System.BitConverter. So messages look like this (english):

Here's 512 bytes:
[data]
Here's 512 bytes:
[data]
Here's 32 bytes:
[data]
Here's 4 bytes:
That was the whole file

The advantage here is that you can make the copy/read buffers work for you (reading 512 bytes at a time), meaning your throughput is limited by your network stack instead of your C# code. The client reads the fixed-length 32-bit int that lets it know the size of the buffer it should use for the next [data] segment.

Here's some code to write messages like that:

        logger.logger.debug("Sending message of length " + length);
        byte[] clength = System.BitConverter.GetBytes(buffer.Length);
        plaintextStream.Write(clength,0,clength.Length);
        plaintextStream.Write(buffer,0,buffer.Length);
        plaintextStream.Flush();

And here's some code to read them:

               byte[] intbuf = new byte[int_32_size];
        int offset = 0;
        while (offset < int_32_size)
        {
            int read = 0;

            read = d.plaintextStream.Read(intbuf,offset,int_32_size - offset);
            offset += read;

        }
        int msg_size = System.BitConverter.ToInt32(intbuf,0);
        //allocate a new buffer to fill the message
        byte[] msg_buffer = new byte[msg_size];
        offset = 0;
        while (offset < msg_size)
        {
            int read = 0;

            read = d.plaintextStream.Read(msg_buffer,offset,msg_size - offset);
            offset += read;
        }


        return msg_buffer;
花开半夏魅人心 2024-08-08 19:21:50

要传输文件/数据,您可以使用 TcpClient /TcpListener 类,这是对 grittier 套接字功能的很好的抽象。 或者,您可以简单地使用 将应用程序作为 HTTP 服务器HttpListener 类,如果这更容易/更适合您的应用程序。

对于发现,如果您能够拥有中央服务器; 那么你可以让每个客户端在启动时连接到服务器,注册自己并检索其他在线客户端及其 IP 的列表。 随后的通信可以直接在客户端之间进行。

该方案的一种变体是让中央服务器充当代理,客户端之间的所有流量都流经该代理。 如果客户端不在同一网络上,这对于克服防火墙或路由问题非常有帮助(因此您的场景可能不需要)。

For transferring the files / data, you can use the TcpClient/TcpListener classes, which is nice abstractions over the grittier socket functionality. Or, you could simply have the application as a HTTP server using the HttpListener class, if that is easier/more appropiate for your application.

For discovery, if you are able to have a central server; then you could have each client connect to the server at startup, to register itself and retrieve a list of other online clients and their IP's. Subsequent communication can then take place directly between the clients.

A variation of this scheme, is to let the central server act as a proxy, which all traffic between the clients flow through. This would be mostly helpful to overcome firewall or routing issues if the clients is not on the same network (so it's propably not needed for your scenario).

诗化ㄋ丶相逢 2024-08-08 19:21:50

要复制文件,您可能还需要查看文件同步提供程序,它是 Microsoft Sync Framework 的一部分。 http://msdn.microsoft.com/en-us/sync/bb887623

To copy files you may also want to look at File Synchronization Provider that is part of Microsoft Sync Framework. http://msdn.microsoft.com/en-us/sync/bb887623.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文