C# 通过单个端口传输多种数据类型(接收)
C# Transferring multiple data types over a single port (receiving)
问题
前几天,我对 C# 应用程序 有了一个 "amazing" 的想法。我不想为每种数据类型(文本、图像、文件)使用一个端口,而是想为所有三种数据类型使用一个单个端口 .我非常接近实现这个。
到目前为止,我有一个 TcpListener 监听端口 23722。当 TcpClient 连接时,我开始使用 StreamWriter.Write(datareceived);
将传入数据写入文件,数据以特定模式出现(每行代表一个图像、文本消息或文件):
dnett{This is a sample text message.)
dneti{NLtqmuvtGBdDY546 ... NLtqmuvtGBdDY546}
dnetf{Example.exe,NLtqmuvtGBdDY546 ... NLtqmuvtGBdDY546}
正如您从上面看到的图像和文件 在发送之前被转换为 Base64。要将它们转换回来,我会使用 byte[] tmp = Convert.FromBase64String(string)
,但问题是当数据仍在传入时,我无法逐行读取文件 (用 StreamWriter)。另一个问题是,我不知道哪些数据已被处理(例如:哪些文件已被写入文件系统)。
我需要的是:
- 同时解决reading/writing个文件
- 知道哪些数据已经被处理了
或
- 另一种方法(不同的方法)
谢谢
顺便说一句,我只有 15 岁,英语不是我的第一语言,所以对于可能愚蠢的问题和上述问题中的错误,我深表歉意。
我也是初学者。但我认为您可以使用 ArrayList 来转换所有行,直到所有行都被读取和发送。因此,当您准备好并且文件已全部读取时,您可以保存它。如果您要问如何知道先发送哪种文件,请发送一个文件,您可以发送一个字符或一个字符串,以允许等待文件的其他程序识别将要恢复的文件。请原谅我的英语。我希望我能对你有所帮助。
通常,您会先发送 "message" 的大小,然后再发送实际的 "message"(来自服务器)。您可以将此扩展为先发送您的消息类型的大小,然后发送您的消息类型,然后发送实际消息的大小,然后发送该消息。
要回读,您需要这样做
using System;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using Newtonsoft.Json;
using Unity3DRemoteRendererClient.Helpers;
namespace Unity3DRemoteRendererClient.Communications.TCPCommunication {
public sealed partial class TCPClientManager {
public sealed class Receiver {
private NetworkStream _stream;
private Thread _thread;
//Subscribe to this event if you want an event ever time data arrives.
public event EventHandler < UnityToClientMessage > DataReceivedEvent;
private static ManualResetEvent ShutDownEvent = new ManualResetEvent(false);
public void Start(NetworkStream stream) {
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run() {
try {
// ShutdownEvent is a ManualResetEvent signaled by
// Client when its time to close the socket.
while (!ShutDownEvent.WaitOne(0)) {
try {
if (!_stream.DataAvailable) continue;
//Read the first 4 bytes which represent the size of the message, and convert from byte array to int32
var sizeinfo = new byte[4];
_stream.Read(sizeinfo, 0, 4);
var messageSize = BitConverter.ToInt32(sizeinfo, 0);
//create a new buffer for the data to be read
var buffer = new byte[messageSize];
var read = 0;
//Continue reading from the stream until we have read all bytes @messageSize
while (read != messageSize) {
read += _stream.Read(buffer, read, buffer.Length - read);
}
//I use flatbuffers, so you should deserialize yourself.
var message = new UnityToClientMessage().FlatDeserialize(buffer);
//raise data received event
OnDataReceived(message);
} catch (IOException ex) {
// Handle the exception...
throw;
}
}
} catch (Exception ex) {
// Handle the exception...
throw;
} finally {
_stream.Close();
}
}
private void OnDataReceived(UnityToClientMessage e) {
EventHandler < UnityToClientMessage > handler = DataReceivedEvent;
if (handler != null) {
handler(this, e);
}
}
public void ShutDown() {
ShutDownEvent.Set();
}
}
}
}
只需修改为先读取消息类型消息的大小,再读取实际消息即可。一旦收到描述即将到来的消息类型的消息,就可以执行 switch 语句,并相应地处理它。
问题
前几天,我对 C# 应用程序 有了一个 "amazing" 的想法。我不想为每种数据类型(文本、图像、文件)使用一个端口,而是想为所有三种数据类型使用一个单个端口 .我非常接近实现这个。
到目前为止,我有一个 TcpListener 监听端口 23722。当 TcpClient 连接时,我开始使用 StreamWriter.Write(datareceived);
将传入数据写入文件,数据以特定模式出现(每行代表一个图像、文本消息或文件):
dnett{This is a sample text message.)
dneti{NLtqmuvtGBdDY546 ... NLtqmuvtGBdDY546}
dnetf{Example.exe,NLtqmuvtGBdDY546 ... NLtqmuvtGBdDY546}
正如您从上面看到的图像和文件 在发送之前被转换为 Base64。要将它们转换回来,我会使用 byte[] tmp = Convert.FromBase64String(string)
,但问题是当数据仍在传入时,我无法逐行读取文件 (用 StreamWriter)。另一个问题是,我不知道哪些数据已被处理(例如:哪些文件已被写入文件系统)。
我需要的是:
- 同时解决reading/writing个文件
- 知道哪些数据已经被处理了
或
- 另一种方法(不同的方法)
谢谢
顺便说一句,我只有 15 岁,英语不是我的第一语言,所以对于可能愚蠢的问题和上述问题中的错误,我深表歉意。
我也是初学者。但我认为您可以使用 ArrayList 来转换所有行,直到所有行都被读取和发送。因此,当您准备好并且文件已全部读取时,您可以保存它。如果您要问如何知道先发送哪种文件,请发送一个文件,您可以发送一个字符或一个字符串,以允许等待文件的其他程序识别将要恢复的文件。请原谅我的英语。我希望我能对你有所帮助。
通常,您会先发送 "message" 的大小,然后再发送实际的 "message"(来自服务器)。您可以将此扩展为先发送您的消息类型的大小,然后发送您的消息类型,然后发送实际消息的大小,然后发送该消息。
要回读,您需要这样做
using System;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using Newtonsoft.Json;
using Unity3DRemoteRendererClient.Helpers;
namespace Unity3DRemoteRendererClient.Communications.TCPCommunication {
public sealed partial class TCPClientManager {
public sealed class Receiver {
private NetworkStream _stream;
private Thread _thread;
//Subscribe to this event if you want an event ever time data arrives.
public event EventHandler < UnityToClientMessage > DataReceivedEvent;
private static ManualResetEvent ShutDownEvent = new ManualResetEvent(false);
public void Start(NetworkStream stream) {
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run() {
try {
// ShutdownEvent is a ManualResetEvent signaled by
// Client when its time to close the socket.
while (!ShutDownEvent.WaitOne(0)) {
try {
if (!_stream.DataAvailable) continue;
//Read the first 4 bytes which represent the size of the message, and convert from byte array to int32
var sizeinfo = new byte[4];
_stream.Read(sizeinfo, 0, 4);
var messageSize = BitConverter.ToInt32(sizeinfo, 0);
//create a new buffer for the data to be read
var buffer = new byte[messageSize];
var read = 0;
//Continue reading from the stream until we have read all bytes @messageSize
while (read != messageSize) {
read += _stream.Read(buffer, read, buffer.Length - read);
}
//I use flatbuffers, so you should deserialize yourself.
var message = new UnityToClientMessage().FlatDeserialize(buffer);
//raise data received event
OnDataReceived(message);
} catch (IOException ex) {
// Handle the exception...
throw;
}
}
} catch (Exception ex) {
// Handle the exception...
throw;
} finally {
_stream.Close();
}
}
private void OnDataReceived(UnityToClientMessage e) {
EventHandler < UnityToClientMessage > handler = DataReceivedEvent;
if (handler != null) {
handler(this, e);
}
}
public void ShutDown() {
ShutDownEvent.Set();
}
}
}
}
只需修改为先读取消息类型消息的大小,再读取实际消息即可。一旦收到描述即将到来的消息类型的消息,就可以执行 switch 语句,并相应地处理它。