具有 binary/byte[] 流的 SocketAsyncEventArgs
SocketAsyncEventArgs with binary/byte[] streams
我是 C# 和套接字的新手,所以如果我的问题不合时宜,我深表歉意。我开始使用 link 中的示例构建套接字接口:
https://code.msdn.microsoft.com/High-Performance-NET-69c2df2f
我希望能够通过套接字传输二进制文件,所以我做了一个假设(也许是错误的假设)我不应该使用 StringBuilder
。我将原来的 OSUserToken
更改为使用 MemoryStream
和 BinaryWriter
(注释掉原始代码)。
在代码的其他地方(来自上面的 link),SocketAsyncEventArgs
被初始化为 SetBuffer(new Byte[_bufferSize], 0, _bufferSize);
。我担心这不会与我的 MemoryStream
和 BinaryWriter
很好地融合,但它似乎有效。
sealed class UserToken : IDisposable
{
private Socket _ownerSocket;
public Socket ownerSocket { get { return _ownerSocket; } }
private MemoryStream _memoryStream;
private BinaryWriter _binaryWriter;
//private StringBuilder stringbuilder;
private int totalByteCount;
public String LastError;
public UserToken(Socket readSocket, int bufferSize)
{
_ownerSocket = readSocket;
_memoryStream = new MemoryStream();
_binaryWriter = new BinaryWriter(_memoryStream);
//stringbuilder = new StringBuilder(bufferSize);
}
// Do something with the received data, then reset the token for use by another connection.
// This is called when all of the data have been received for a read socket.
public void ProcessData(SocketAsyncEventArgs args)
{
String received = System.Text.Encoding.ASCII.GetString(_memoryStream.ToArray());
//String received = stringbuilder.ToString();
Debug.Write("Received: \"" + received + "\". The server has read " + received.Length + " bytes.");
_memoryStream.SetLength(0);
//stringbuilder.Length = 0;
totalByteCount = 0;
}
public bool ReadSocketData(SocketAsyncEventArgs readSocket)
{
int byteCount = readSocket.BytesTransferred;
/*
if ((totalByteCount + byteCount) > stringbuilder.Capacity)
{
LastError = "Receive Buffer cannot hold the entire message for this connection.";
return false;
}
else
{
*/
//stringbuilder.Append(Encoding.ASCII.GetString(readSocket.Buffer, readSocket.Offset, byteCount));
_binaryWriter.Write(readSocket.Buffer,readSocket.Offset,byteCount);
totalByteCount += byteCount;
return true;
/*}*/
}
public void Dispose()
{
_memoryStream.Dispose();
_binaryWriter.Dispose();
try
{
_ownerSocket.Shutdown(SocketShutdown.Both);
}
catch
{
//Nothing to do here, connection is closed already
}
finally
{
_ownerSocket.Close();
}
}
}
当我运行这个时,它似乎没有问题。即使我设置 protected const int DEFAULT_BUFFER_SIZE = 1
它也会接受 >1 字节的流:
17:11:20:433 - Debug - Initializing the listener on port 5000...
17:11:20:439 - Debug - Starting the listener...
17:11:20:444 - Debug - Server started.
17:11:31:856 - Debug - Received: "listener". The server has read 8 bytes.
17:11:33:264 - Debug - Received: "l". The server has read 1 bytes.
17:11:33:268 - Debug - Received: "istener". The server has read 7 bytes.
17:11:36:744 - Debug - Received: "l". The server has read 1 bytes.
17:11:36:744 - Debug - Received: "i". The server has read 1 bytes.
17:11:36:746 - Debug - Received: "stener". The server has read 6 bytes.
我的问题是:
StringBuilder
不适用于二进制文件,我应该使用 MemoryStream
和 BinaryWriter
吗?
- 如果在程序的其他地方
SocketAsyncEventArgs
是用 SetBuffer(new Byte[_bufferSize], 0, _bufferSize);
初始化的,我是否需要担心缓冲区溢出?
- 如果我必须遵守缓冲区大小限制,我是否需要对发送数据的客户端设置相同的缓冲区限制?
我找到了问题的答案
StringBuilder
工作正常。只需在发送前对 base64
中的字符串进行编码,并在接收后进行解码。无论发送文本还是二进制数据都应该这样做。看我下面写的class
- 仍然不知道这个问题的答案,但看到
StringBuilder
& base64
适用于二进制,此问题不再相关。
- 我认为这个问题的答案是肯定的。客户端应具有最大消息长度。我根据我定义消息长度的套接字的 header 部分进行控制。 header 是固定长度,我的最大消息长度是
0xFFFFF
.
Class 对于 encoding/decoding base64:
public static class Base64
{
public static string EncodeBase64(string text)
{
return System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(text));
}
public static string EncodeBase64(byte[] array)
{
return System.Convert.ToBase64String(array);
}
public static string DecodeBase64ToString(string base64String)
{
return System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(base64String));
}
public static Byte[] DecodeBase64ToBinary(string base64String)
{
Byte[] bytes = System.Convert.FromBase64String(base64String);
return bytes;
}
}
我是 C# 和套接字的新手,所以如果我的问题不合时宜,我深表歉意。我开始使用 link 中的示例构建套接字接口: https://code.msdn.microsoft.com/High-Performance-NET-69c2df2f
我希望能够通过套接字传输二进制文件,所以我做了一个假设(也许是错误的假设)我不应该使用 StringBuilder
。我将原来的 OSUserToken
更改为使用 MemoryStream
和 BinaryWriter
(注释掉原始代码)。
在代码的其他地方(来自上面的 link),SocketAsyncEventArgs
被初始化为 SetBuffer(new Byte[_bufferSize], 0, _bufferSize);
。我担心这不会与我的 MemoryStream
和 BinaryWriter
很好地融合,但它似乎有效。
sealed class UserToken : IDisposable
{
private Socket _ownerSocket;
public Socket ownerSocket { get { return _ownerSocket; } }
private MemoryStream _memoryStream;
private BinaryWriter _binaryWriter;
//private StringBuilder stringbuilder;
private int totalByteCount;
public String LastError;
public UserToken(Socket readSocket, int bufferSize)
{
_ownerSocket = readSocket;
_memoryStream = new MemoryStream();
_binaryWriter = new BinaryWriter(_memoryStream);
//stringbuilder = new StringBuilder(bufferSize);
}
// Do something with the received data, then reset the token for use by another connection.
// This is called when all of the data have been received for a read socket.
public void ProcessData(SocketAsyncEventArgs args)
{
String received = System.Text.Encoding.ASCII.GetString(_memoryStream.ToArray());
//String received = stringbuilder.ToString();
Debug.Write("Received: \"" + received + "\". The server has read " + received.Length + " bytes.");
_memoryStream.SetLength(0);
//stringbuilder.Length = 0;
totalByteCount = 0;
}
public bool ReadSocketData(SocketAsyncEventArgs readSocket)
{
int byteCount = readSocket.BytesTransferred;
/*
if ((totalByteCount + byteCount) > stringbuilder.Capacity)
{
LastError = "Receive Buffer cannot hold the entire message for this connection.";
return false;
}
else
{
*/
//stringbuilder.Append(Encoding.ASCII.GetString(readSocket.Buffer, readSocket.Offset, byteCount));
_binaryWriter.Write(readSocket.Buffer,readSocket.Offset,byteCount);
totalByteCount += byteCount;
return true;
/*}*/
}
public void Dispose()
{
_memoryStream.Dispose();
_binaryWriter.Dispose();
try
{
_ownerSocket.Shutdown(SocketShutdown.Both);
}
catch
{
//Nothing to do here, connection is closed already
}
finally
{
_ownerSocket.Close();
}
}
}
当我运行这个时,它似乎没有问题。即使我设置 protected const int DEFAULT_BUFFER_SIZE = 1
它也会接受 >1 字节的流:
17:11:20:433 - Debug - Initializing the listener on port 5000...
17:11:20:439 - Debug - Starting the listener...
17:11:20:444 - Debug - Server started.
17:11:31:856 - Debug - Received: "listener". The server has read 8 bytes.
17:11:33:264 - Debug - Received: "l". The server has read 1 bytes.
17:11:33:268 - Debug - Received: "istener". The server has read 7 bytes.
17:11:36:744 - Debug - Received: "l". The server has read 1 bytes.
17:11:36:744 - Debug - Received: "i". The server has read 1 bytes.
17:11:36:746 - Debug - Received: "stener". The server has read 6 bytes.
我的问题是:
StringBuilder
不适用于二进制文件,我应该使用MemoryStream
和BinaryWriter
吗?- 如果在程序的其他地方
SocketAsyncEventArgs
是用SetBuffer(new Byte[_bufferSize], 0, _bufferSize);
初始化的,我是否需要担心缓冲区溢出? - 如果我必须遵守缓冲区大小限制,我是否需要对发送数据的客户端设置相同的缓冲区限制?
我找到了问题的答案
StringBuilder
工作正常。只需在发送前对base64
中的字符串进行编码,并在接收后进行解码。无论发送文本还是二进制数据都应该这样做。看我下面写的class- 仍然不知道这个问题的答案,但看到
StringBuilder
&base64
适用于二进制,此问题不再相关。 - 我认为这个问题的答案是肯定的。客户端应具有最大消息长度。我根据我定义消息长度的套接字的 header 部分进行控制。 header 是固定长度,我的最大消息长度是
0xFFFFF
.
Class 对于 encoding/decoding base64:
public static class Base64
{
public static string EncodeBase64(string text)
{
return System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(text));
}
public static string EncodeBase64(byte[] array)
{
return System.Convert.ToBase64String(array);
}
public static string DecodeBase64ToString(string base64String)
{
return System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(base64String));
}
public static Byte[] DecodeBase64ToBinary(string base64String)
{
Byte[] bytes = System.Convert.FromBase64String(base64String);
return bytes;
}
}