How to send length of a package via tcp/ip protocol
I'm doing this for one of my school projects. I'm trying to design a multi-threaded server that accepts clients for working with a database (adding, deleting records etc). When I connect the client to the server I want to receive all the students in my database.
I access the database on the Server Side and store the information in an ArrayList, which I'm trying to send it over the network. I don't have any knowledge on XMLserializing so I'm trying to send each string in the arrayList to the client. When I send the data from the server, I开发者_运维百科 sometimes receive all the data in the same time, sometimes I don't, so my first guess was that I have to split the data I send into packages of some length. I don't see how can I add the length at the beginning of a package. Wouldn't it be the same thing? Maybe I get the correct length maybe I don't.
Here is my code; I didn't try sending the length of each package yet, because I have no idea how. I tried sending from the server the length of the arraylist, and read from the network stream that many times, but it doesn't work ( I receive all data in one package).
Server side:
private void HandleClient(object client)
{
try
{
ClientNo++;
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] bytes = new byte[4096];
int i;
// Robot r = new Robot();
Protocol p = new Protocol();
ArrayList ListaStudentiResponse = p.ExecuteQueryOnStudents("select * from studenti");
byte[] Length = new byte[4];
Length = System.Text.Encoding.ASCII.GetBytes(ListaStudentiResponse.Count.ToString());
clientStream.Write(Length, 0, Length.Length);
foreach ( String s in ListaStudentiResponse)
{
byte[] data = System.Text.Encoding.ASCII.GetBytes(s);
clientStream.Write(data, 0, data.Length);
}
tcpClient.Close();
ClientNo--;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
On Client:
private void connectToServerToolStripMenuItem_Click(object sender, EventArgs e)
{
tcpclient = new TcpClient();
NetworkStream netStream;
try
{
tcpclient.Connect("localhost", 8181);
netStream = tcpclient.GetStream();
Byte[] bytes = new Byte[10000];
int readBytes = netStream.Read(bytes, 0, bytes.Length);
int Length =Int32.Parse(Encoding.ASCII.GetString(bytes, 0, readBytes));
MessageBox.Show(Length.ToString());
int i = 0;
while (i < Length)
{
i++;
Byte[] b = new Byte[10000];
readBytes = netStream.Read(bytes, 0, bytes.Length);
String response = Encoding.ASCII.GetString(b, 0, readBytes);
MessageBox.Show(response);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
You can use a StateObject to keep track of how large your data is, and then test during ReadCallback to see if you have "all" of the message. If you don't have all of your message, you call BeginRecieve again with the current StateObject.
Here is a decent example: http://www.csharphelp.com/2007/02/asynchronous-server-socket-using-c/
This is what I been using:
How to use the buffer on SocketAsyncEventArgs object
Look at the accepted answer. 1st off, this is using something call completion port which is highly efficient than async. Secondly, I find that it is very easy to troubleshoot by looking at e.SocketError
to find out the exact cause for failure.
How it works is that for your message to send, append the message with a header and trailer.
So when it receive the message, it will check if the trailer is received. If trailer not received, it will continue receive for that client, and append the received message to the stringBuilder object. Once the trailer is received, just call stringbuilder.toString() to get the whole content.
精彩评论