Reputation:
basically What I need is a p2p connection, right now I have a asynchronous server and client which is communicating between each other via TcpClient
s. Problem is the server rarely detects incoming messages, and usually only recieves the first message. My server code is here :
public void RecieveAsync()
{
if (netStream == null) netStream = Server.GetStream();
netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);
}
public void recieveCallBack(IAsyncResult ar)
{
//try
//{
int rec = netStream.EndRead(ar);
if (rec == 0)
{
if (Disconnected != null)
{
Disconnected(this);
return;
}
}
else
{
if (DataRecieved != null)
{
string RecievedData = Encoding.ASCII.GetString(ReadBuffer, 0, rec);
DataRecieved(RecievedData);
}
ReadBuffer = new byte[1024];
}
}
and the client code sending the data is here (Which is wrapped into a while loop sending data over and over with a Thread.Sleep(1)
, to update the players position )
public void Send(byte[] data, int index, int length)
{
//add data as state
//socket.NoDelay = true;
Buffer.BlockCopy(data, 0, writeBuffer, index, length);
if (netStream == null) netStream = TcpClient.GetStream();
netStream.BeginWrite(writeBuffer, 0, writeBuffer.Length, sendCallback, netStream);
}
private void sendCallback(IAsyncResult ar)
{
//try
//{
netStream.EndWrite(ar);
//if (ar.AsyncState != null)
//{
// byte[] buffer = (byte[])ar.AsyncState;
// socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, sendCallback, null);
// return;
//}
if (OnSend != null)
{
OnSend(this);
}
//catch (Exception ex)
//{
// System.Windows.Forms.MessageBox.Show(ex.ToString());
// return;
//}
}
The default buffer size is 1024, and RecieveAsync
is only called when netStream.DataAvailible
is true, which is constantly checking in the server loop.
Edit ::
This is the code which calls the server
while (true)
{
byte[] playerData = NormalText(PreparePlayerData());
server.Send(playerData, 0, playerData.Length);
if (server.Server.Connected)
{
server.netStream = server.Server.GetStream();
while (server.netStream.DataAvailable)
{
server.RecieveAsync();
server.netStream = server.Server.GetStream();
}
}
Thread.Sleep(1);
}
Upvotes: 0
Views: 2614
Reputation: 3299
When it comes to network programming it helps to know what is going on behind the various method. In the case of your receive method you correctly configure the callback using
netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);
This will trigger recieveCallBack() when data is received but the following line is where it starts to get interesting. It's also worth noting that a single call to netStream.BeginRead will only trigger the callback once. Should you want to continue listening for data you need to call netStream.BeginRead again.
string RecievedData = Encoding.ASCII.GetString(ReadBuffer, 0, rec);
The framework does not guarantee you will receive all of the data you write in the send. Once you have received some data you need to decide it you have everything before you try to convert it back to a string. If you have not received everything you need to make another call to
netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);
and then wait for more.
This is a tricky aspect of programming but you are obviously well on your way. If it helps to work backwards from a working example checkout the method IncomingTCPPacketHandler() (equivalent of your recieveCallBack method) here which is from the open source network library networkcomms.net.
Upvotes: 1