我必须使用TCP通信在项目中集成2个系统 - 开发了自定义协议。
通过协议发送的消息如下所示:
MsgLength - 10 positions (in chars, not bytes)
MessageType - 20 positions
Message Number - 9 positions
Timestamp - 19 positions
version - 2 positions
Body - variable (depending on first field)
我正在研究Socket编程,但我想知道等待完整的msg到达的最佳方法是什么。可能我需要将字节转换为剩余的字符数。因为套接字API仅适用于字节。
欢迎所有提示,代码示例,博客文章: - )
编辑:这是我的第一个版本的代码,我使用的是Async方法,因为多个客户端可以同时连接。
private static void Listen()
{
while (true)
{
//TcpClient client = _listener.AcceptTcpClient();
allDone.Reset();
_listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), _listener);
allDone.WaitOne();
}
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
//TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient handler = _listener.EndAcceptTcpClient(ar);
// Create the state object.
StateObject state = new StateObject();
state.client = handler;
handler.GetStream().BeginRead(state.buffer, 0, StateObject.BufferSize, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
Encoding enc = Encoding.GetEncoding("ISO-8859-1");
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
TcpClient handler = state.client;
int bytesRead = handler.GetStream().EndRead(ar);
state.TotalHeaderBytesRead += bytesRead;
if (bytesRead == 60)
{
string header = enc.GetString(state.buffer);
Header h = HeaderParser.Parse(header);
//todo read the body
byte[] bodyBuffer = new byte[((HeaderPlaPo)h).Length - 60];
state.buffer = bodyBuffer;
handler.GetStream().BeginRead(state.buffer, 0, bodyBuffer.Length, new AsyncCallback(ReadBodyCallback), state);
Logger.Log(string.Format("received header {0}", header), System.Diagnostics.TraceLevel.Info);
}
else
{
// Not all data of header received. Get more.
handler.GetStream().BeginRead(state.buffer, 0, StateObject.BufferSize - state.TotalHeaderBytesRead, new AsyncCallback(ReadHeaderCallback), state);
}
}
public static void ReadBodyCallback(IAsyncResult ar)
{
Encoding enc = Encoding.GetEncoding("ISO-8859-1");
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
TcpClient handler = state.client;
int bytesRead = handler.GetStream().EndRead(ar);
int bytesRead = handler.GetStream().EndRead(ar);
state.TotalBodyBytesRead += bytesRead;
if (state.buffer.Length == state.TotalBodyBytesRead)
{ // todo我们收到了所有 string body = enc.GetString(state.buffer); Logger.Log(string.Format(“received body {0}”,body),System.Diagnostics.TraceLevel.Info); } 其他 { handler.GetStream()。BeginRead(state.buffer,bytesRead,state.buffer.Length - state.TotalBodyBytesRead,ReadBodyCallback,state); } }
公共类StateObject { //客户端套接字 public TcpClient client = null; //接收缓冲区的大小。 public static int BufferSize = 60; //接收缓冲区。 public byte [] buffer = new byte [BufferSize]; //收到数据字符串 public StringBuilder sb = new StringBuilder(); //头 public Header标题; 公共身体; public Int32 TotalBodyBytesRead; public Int32 TotalHeaderBytesRead; }
此代码适用于发送数据并关闭连接的客户端,但是当使用连接的客户端多次发送时,数据不会被读取 - >我应该在读完整个身体后关闭连接吗?
答案 0 :(得分:1)
您没有提到您使用的语言,我用Java提供示例,如果您需要其他语言,请告诉我。无论如何,你需要在一次关闭中读取60(10 + 20 + 9 + 19 + 2)个字节。将10个第一个字节(字符)转换为整数,然后将该字节数读入byte []数组。
例如:
try
{
byte[] buffer = new byte[60];
mySocket.getInputStream().read(buffer, 0, 60);
String header = buffer.toString();
int length = Integer.parseInt(header.substring(0, 9));
byte[] body = new byte[length];
mySocket.getInputStream().read(body, 0, length);
}
catch (Exception e)
{
e.printStackTrace();
}
编辑:改为C#
byte[] buffer = new byte[60];
mySocket.Receive(buffer, 60, SocketFlags.None);
// You should ckeck this, UTF7 or UTF8 or UNICODE, etc
string header = Encoding.UTF7.GetString(buffer, 0, 60);
int length = Convert.ToInt32(header.Substring(0, 10));
byte[] body = new byte[length];
int offset=0;
// Keep reading the socket until all bytes has been received
while (length > 0)
{
int ret=mySocket.Receive(body, offset, length, SocketFlags.None);
if (ret > 0)
{
offset += ret;
length -= ret;
}
else
if (ret == 0)
{
// peer has close the socket
}
else
{
// there is an error in the socket.
}
}