Need help with a C# Asynchronous Socket Program that has multiple sends - c#

So, I have a board game that uses Asynchronous socket to operate over LAN. The thing is, I have little to no understanding of Asynchronous socket programming, or of threads, but I do my best to try.
I based my program off a chat program, so I use that part to send multiple strings.
So, here's part of the code for the Client:
private void Connect(IAsyncResult iar)
{
try
{
Socket client_conn = (Socket)iar.AsyncState;
client_conn.EndConnect(iar);
g_bmsg = new byte[1024];
check = true;
string szData = "#Player " + lblName.Text + " connected.";
sendingFunction(szData);
g_client_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Receive), g_client_conn);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "GG");
}
}
private void Send(IAsyncResult iar)
{
Socket client_conn = (Socket)iar.AsyncState;
client_conn.EndSend(iar);
}
private void Receive(IAsyncResult iar)
{
if (g_bmsg.Length != 0)
{
SetLabelText(Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
check = false;
}
}
private void SetLabelText(string txt)
{
if (lblBuffer.InvokeRequired)
lblBuffer.Invoke(new MethodInvoker(delegate { SetLabelText(txt); }));
else
{
lblBuffer.Text = txt;
}
if (lblBuffer.Text.StartsWith("#"))
{
lblStatmsg.Text = lblBuffer.Text.Replace("#", "");
}
if (lblBuffer.Text.StartsWith("$"))
{
lblStatmsg.Text = "Server Settings Received.";
lblBuffer.Text = lblBuffer.Text.Replace("$", "");
option_Postn = int.Parse(lblBuffer.Text.Substring(0, 1));
option_First = int.Parse(lblBuffer.Text.Substring(2, 1));
}
if (lblBuffer.Text.StartsWith("#"))
{
MessageBox.Show(lblBuffer.Text);
}
}
And here's part of the code for the Server:
private void Accept(IAsyncResult iar)
{
Socket server_conn = (Socket)iar.AsyncState;
g_server_conn = server_conn.EndAccept(iar);
g_bmsg = new byte[1024];
check = true;
g_server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), g_server_conn);
}
private void Send(IAsyncResult iar)
{
Socket server_conn = (Socket)iar.AsyncState;
server_conn.EndSend(iar);
}
private void Recieve(IAsyncResult iar)
{
try
{
Socket server_conn = (Socket)iar.AsyncState;
server_conn.EndReceive(iar);
if (g_bmsg.Length != 0)
{
SetLabelText(Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
check = false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "GG");
}
}
private void SetLabelText(string txt)
{
if (lblBuffer.InvokeRequired)
lblBuffer.Invoke(new MethodInvoker(delegate { SetLabelText(txt); }));
else
{
lblBuffer.Text = txt;
}
if (lblBuffer.Text.StartsWith("#"))
{
lblStatmsg.Text = lblBuffer.Text.Replace("#", "");
}
else if (lblBuffer.Text.StartsWith("#"))
{
MessageBox.Show(lblBuffer.Text);
}
else if (lblBuffer.Text.StartsWith("%"))
{
}
}
Basically, since the game sends more than messages (it can send settings, or game pieces, etc), I ran the sender function everytime I need to send something, and on the other side, the Receiver decodes the string sent based on the first character (# means the string is a setting, for example).
The problem is, after the first time both host and client sent something to one another, they can't seem to send again. No error, no message, no nothing. Just won't send. Is there something wrong with the sendingFunction? Or perhaps the delegate something? I don't know. Some advice would be appreciated, guys. And thanks in advance.

You're never calling BeginReceive again. The typical practice in async socket programming is to process the received data, then call BeginReceive again so that you can then process the next bit of data that comes in.

Related

system.net.sockets.socketexception the remote server closed connection

I have this code on my server side.
public static void Data_IN(object cSocket)
{
Socket clientSocket = (Socket)cSocket;
byte[] Buffer;
int readBytes;
while (true)
{
Buffer = new byte[clientSocket.SendBufferSize];
readBytes = clientSocket.Receive(Buffer);
if (readBytes > 0)
{
Packet p = new Packet(Buffer);
DataManager(p);
}
}
}
And the main problem is that when I stop debugging the code the server always crashes and says
System.Net.Sockets.SocketException: the remote server closed connection
The error is always at readBytes = clientSocket.Recieve(Buffer);
That is the only way I can crash the server, my only concern is when someone uses the chat program that I have created and his/hers computer crashes the chat server will go down and I always need to restart the server.
Clientside code below which executes when closing the window
private void MainWindow_Closed(object sender, EventArgs e)
{
if (isConnected)
{
Packet p = new Packet(PacketType.CloseConnection, ID);
p.data.Add(login);
p.data.Add("exits from chat");
socket.Send(p.ToBytes());
socket.Close();
isConnected = false;
thread.Abort();
}
}
On below there is the code part which uses data_in, that code is on the client side
private void ConnectBtn_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(Login.Text))
{
MessageBox.Show("Add username");
}
else if (!IPAddress.TryParse(serverIP.Text, out ipAdress))
{
MessageBox.Show("Add valid ip");
}
else
{
ClearRequireMsg();
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(ipAdress, 4242);
try
{
socket.Connect(ipEndPoint);
login = Login.Text;
isConnected = true;
ConnectBtn.IsEnabled = false;
SendBtn.IsEnabled = true;
thread = new Thread(Data_IN);
thread.Start();
}
catch (SocketException ex)
{
AddMsgToBoard("Error during connecting to server", "System");
}
}
}
You're calling the function Data_IN without passing any parameter.
thread = new Thread(Data_IN);
Right way:
new Thread(() => Data_IN(socket));

How to read complete data packet one time in TCP

I have a C# application which accepts data from a port(9100 ie, uses data when printer print something) and use it into an application. The problem is, sometimes it doesn't receiving data completely from printer and I have seen some questions regarding the difficulties in reading data at one time in TCP.
As I am not familiar with this, somebody please suggest me a better way to fix it.
Thanks in advance..
Here is my code
TcpListener Listener = null;
public Thread T = null;
public FeederControlMonitor()
{
InitializeComponent();
}
private void FeederControlMonitor_Load(object sender, EventArgs e)
{
txtStatus.Text = "Feeder waiting for data...";
ThreadStart Ts = new ThreadStart(StartReceiving);
T = new Thread(Ts);
T.Start();
}
public void StartReceiving()
{
ReceiveTCP(9100);
}
public void ReceiveTCP(int portN)
{
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\Drive\\ex.txt", ex.Message);
Console.WriteLine(ex.Message);
}
try
{
while (true)
{
Socket client = Listener.AcceptSocket();
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[20000];
int size = client.Receive(data);
ParseData(System.Text.Encoding.Default.GetString(data));
//Here some process will do with received data
client.Close();
});
childSocketThread.IsBackground = true;
childSocketThread.Start();
}
Listener.Stop();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\ex.txt", ex.Message);
}
}

Using UdpClient, how do you retry UdpClient.Connect() until it succeeds?

My client/server programs work well with each other, but only when the server is up and running before my client starts. If the client fails to connect on the first try, I can't get it to try again.
Here's my Client's connect method.
public void connect()
{
IPAddress server_address = IPAddress.Parse("127.0.0.1");
IPEndPoint server_ip = new IPEndPoint(server_address, 5685);
Console.WriteLine("2");
bool connected = false;
while (!connected)
{
try
{
Console.WriteLine("IN CONNECTED");
udp_client.Connect(server_ip);
byte[] send_data = Encoding.ASCII.GetBytes("INIT");
udp_client.Send(send_data, send_data.Length);
byte[] received_bytes = udp_client.Receive(ref server_ip);
string received_data = Encoding.ASCII.GetString(received_bytes);
if (received_data == "INIT")
{
connected = true;
Console.WriteLine("RECEIVED INIT");
listen(server_ip);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
What I was hoping to see is the udp_client.Connect(server_ip) to loop until I received that "INIT" message from the server.
As it currently stands, there is no loop. It seems to get stuck on udp_client.Receive(ref server_ip).
Any help would be appreciated!
This is pseudoCode - you will have to move somethings to class scope to allow future send/receives (which you'd do using a different method). This is only designed to show you how to connect when the connection blocks:
bool isClientConnected = false;
var connector = new System.ComponentModel.BackgroundWorker();
public void connectToUDP(){
connector.DoWork+= connect;
connector.RunWorkerAsync();
}
private void connect(object sender, DoWorkEventArgs e)
{
IPAddress server_address = IPAddress.Parse("127.0.0.1");
IPEndPoint server_ip = new IPEndPoint(server_address, 5685);
Console.WriteLine("2");
try
{
Console.WriteLine("Waiting for server...");
udp_client.Connect(server_ip);
byte[] send_data = Encoding.ASCII.GetBytes("INIT");
udp_client.Send(send_data, send_data.Length);
byte[] received_bytes = udp_client.Receive(ref server_ip);
string received_data = Encoding.ASCII.GetString(received_bytes);
if (received_data == "INIT")
{
isClietConnected = true;
Console.WriteLine("now connected");
listen(server_ip);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public bool sendReceiveUDP(string send){
if(!isClientConnected){
return false;
}
//perform send
return true;
}
You would then maintain the connected session using class scope and send/receive using a different method. This is for connect only since you only need to do it once.
How you set something like this up:
private bool isConnected = false();
private bool send(){
if(!isConnected){
connect();
}
//send
}
private bool connect(){
if(!isConnected){
//launch connection thread
}
}
private delegate void onNewReceive(string message);
public event onNewReceive onNewReceiveEvent;
public void fireEvent(string message){
onNewReceiveEvent.Invoke(message);
}
private void waitForData(object sender, DoWorkEventArgs e){
//this is the backgroundworker
while(true){
receive();
fireEvent(message);
}
}
Then, subscribe to the onNewREceivedEvent in another class and process the inbound message. onNewReceivedEvent += processInboundMEsasage();
This is all psuedocode and "brain compiled" (creit to others) so it's only meant for demonstrations. Without intellisense, I'm lost.

disconnect/close a client [duplicate]

This question already has an answer here:
C# -- TcpListener.Start() causing SocketException with message "Only one usage of each socket address"
(1 answer)
Closed 2 years ago.
I have a simple client-server application which works like this: the server is always listening (in a separate thread) for a client connection (which sends the name of process that it wants the server to kill).
Here is the server:
private void btnStart_Click(object sender, EventArgs e)
{
_port = int.Parse(comboBoxPorts.SelectedItem.ToString());
_tcpListener = new TcpListener(_ipAddress, _port);
_keepRunning = true;
_listenerThread = new Thread(Listen);
HandleListenerThreadStartListenEvent += HandleListenerThreadStartedEventMethod;
ListenerThreadStartedEvent += HandleListenerThreadStartListenEvent;
_listenerThread.Start();
}
private void btnStop_Click(object sender, EventArgs e)
{
if (_tcpListener != null)
{
_keepRunning = false;
if (_tcpListener.Server.Connected)
{
_tcpListener.Server.Disconnect(true);
}
_tcpListener.Stop();
}
labelServerStatus.Text = "Server is stopped";
comboBoxPorts.Enabled = true;
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void Listen()
{
try
{
_tcpListener.Start();
OnListenerThreadStartListenEvent(); // just update the GUI
}
catch(Exception e)
{
MessageBox.Show("Port " + _port + " is NOT available." + Environment.NewLine +
"Please choose another one: " + e.Message);
return;
}
_keepRunning = true;
string ballonMessage = "Socket Server Running at " + _ipAddress + ", port: " + _port;
notifyIcon1.ShowBalloonTip(2000, "Simplex Listener", ballonMessage, ToolTipIcon.Info);
while (_keepRunning)
{
try
{
#region using AcceptSocket()
_clientSocket = _tcpListener.AcceptSocket();
string checkString = string.Empty;
IPAddress ipOfClient = ((IPEndPoint) _clientSocket.LocalEndPoint).Address;
notifyIcon1.ShowBalloonTip(2000, "Simplex Listener", "New client has connected from ip " + ipOfClient, ToolTipIcon.Info);
byte[] buffer = new byte[SIZE_OF_BUFFER];
int bytesReceived = _clientSocket.Receive(buffer);
// Concatenate chars as bytes to a received string.
for (int i = 0; i < bytesReceived; i++)
checkString += Convert.ToChar(buffer[i]);
//..... getting the name of process and kill it (and than open it...
RestartProcess(nameOfProcess, windowName, pathToExeFile);
// Client is waiting to know operation is complete- so send him some char...
ASCIIEncoding encoder = new ASCIIEncoding();
_clientSocket.Send(encoder.GetBytes("v"));
_clientSocket.Disconnect(true);
_clientSocket.Close();
#endregion
}
catch (Exception )
{
}
}
}
The client side:
public void RestartTheSoftwareInServerComputer(string ipOfServer, int portNumber)
{
TcpClient client = new TcpClient();
if (_serverEndPoint == null)
{
_serverEndPoint = new IPEndPoint(IPAddress.Parse(ipOfServer), portNumber);
}
client.Connect(_serverEndPoint);
// Send the command to the server:
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("....detailsOfProcess....");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
// Now, wait for the server's response [which means the process had been restart].
NetworkStream stream = client.GetStream();
byte[] bytes = new byte[5];
stream.Read(bytes, 0, 5);
string response = Encoding.UTF8.GetString(bytes, 0, 1);
if (response.Equals("x"))
{
throw new Exception("Failed to restart X software.");
}
stream.Close();
client.Close();
}
When I stop and restart the server (when no client had connected), then everything is OK.
The problem is when the server got some client connected, and is restarted, then the client has disconnected and the server needs to be restarted. When we hit the "START SERVER" again it will get the exception:
Only one usage of each socket address (protocol/network address/port)
is normally permitted.
How should I close the port?
When you exit your server, you should call _tcpListener.Stop() to close the main socket that the server is listening on.
Edit: You could also try to call _listenerThread.Join() in your stop button click, to wait for the listener thread to finish, before starting the next one.
private void btnStop_Click(object sender, EventArgs e)
{
if (_tcpListener != null)
{
_keepRunning = false;
if (_tcpListener.Server.Connected)
{
_tcpListener.Server.Disconnect(true);
_tcpListener.Stop();
if (_clientSocket != null)
{
_clientSocket.Close();
_clientSocket = null;
}
_listenerThread.Join();
}
}
labelServerStatus.Text = "Server is stopped";
comboBoxPorts.Enabled = true;
btnStart.Enabled = true;
btnStop.Enabled = false;
}
EDIT 2:
here is a windows form that does similar to your server. I didn't need a client, just use "telnet localhost 49152" from a command prompt to 'pretend' to be the client connecting.
public partial class Form1 : Form
{
private TcpListener _tcpListener;
private bool _keepRunning;
private Thread _listenerThread;
private Socket _clientSocket;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var address = IPAddress.Parse("127.0.0.1");
_tcpListener = new TcpListener(address, 49152);
_keepRunning = true;
_listenerThread = new Thread(Listen);
_listenerThread.Start();
button1.Enabled = false;
button2.Enabled = true;
}
private void Listen()
{
try
{
_tcpListener.Start();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return;
}
_keepRunning = true;
while (_keepRunning)
{
try
{
_clientSocket = _tcpListener.AcceptSocket();
var buffer = new byte[8192];
var bytesReceived = _clientSocket.Receive(buffer);
var checkString = String.Empty;
if (_keepRunning)
{
// bytesReceived can be 0 if the remote socket disconnected
if (bytesReceived > 0)
{
checkString = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
// Client is waiting to know operation is complete- so send him some char...
var encoder = new ASCIIEncoding();
_clientSocket.Send(encoder.GetBytes("v"));
}
if (_clientSocket.Connected) _clientSocket.Disconnect(true);
}
_clientSocket.Close();
}
catch (Exception ex)
{
// really should do something with these exceptions
}
}
}
private void button2_Click(object sender, EventArgs e)
{
if (_tcpListener != null)
{
_keepRunning = false;
if (_tcpListener.Server.Connected)
{
_tcpListener.Server.Disconnect(true);
}
_tcpListener.Stop();
if (_clientSocket != null)
{
_clientSocket.Close();
_clientSocket = null;
}
_listenerThread.Join();
}
button1.Enabled = true;
button2.Enabled = false;
}
}
There are a lot of problems with this code, e.g. sharing variables across threads etc. but on my machine the Join doesn't seem to block for any length of time. The problem with _keepRunning is that on certain systems it's possible for one thread to not see the change from true to false, because it gets optimised or cached. You should really use some form of thread synchronisation, make it volatile, or wrap it in a lock etc. I'd suggest you have a read here about this. I'd also suggest you have a read up on Sockets too, or if as other commenters have mentioned, if you aren't interested in learning about all the idiosyncrasies of sockets and threading, perhaps you should look for a higher level library that hides it all?

C# Networking : Server hangs after receiving more than 65535 bytes

UPDATE:
Due to problems with the admins here on Stackoverflow, I have posted a very trimmed-down version of the same problem on MSDN forum. This text below used MyNetworking.dll, but that is not the problem. Here is a very slimmed Client-Server thing and the problem is exactly the same. Feel free to try it out =)
http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/d3d33eb9-7dce-4313-929e-a8a63d0f1e03
/UPDATE
So, I have a strange error.
Normally, we have a DLL that handles our networking. Lets call that MyNetworking.dll. We use it everywhere in our servers and clients and have done so for 5 years. I haven't had a problem with it, until now.
I have an "XMLPoller", that reads XML from a MySQL database, serializes that into a byte[] array and sends it over the network. These particular XML messages is 627 bytes in serialized form.
The XMLPoller connects to a port on a "remote server" (that happens to be localhost) and sends the packets, one at a time. At exactly packet nbr 105 the connection is closed. 104 packets are sent from XMLPoller and received by the Server. 104 x 627 = 65208 bytes. But packet 105, when the total number of bytes sent would be 65835 the connection is closed with this error:
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
This is the error on the server. However, I have stepped through the XMLPoller (client), and I see when the last 627 bytes are sent (thus sending up til 65835 bytes) and I see no errors on the client, it passes sending without problems.
UPDATE 20:15 SWEDISH TIME
I also get this error in the Client when I debug a little more:
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
I think I have confirmed that it is in the Client the error exists. I am stepping through the code and before any Exceptions are caught on the server, I get an exception on the Client as stated above.
/ENDUPDATE
It seems to me that the Server never receives it, getting the error above. The server gets the connection closed because of something happening on the Client. However, the error on the client is in TCPInput; the stream reading data is dead for some reason?
I am not buffering anything in MyNetworking.dll.
When I get a new connection on a Socket (on the Server), I do this code:
public void setConnected(Socket thisClient)
{
NetworkStream stream = new NetworkStream(thisClient);
socket = thisClient;
output = new TCPOutput(stream, outputHandler,this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
try
{
stream.BeginRead(inputBuffer, 0, 5000, new AsyncCallback(OnDataReceived), null);
}
catch (Exception e)
{
this.disconnect();
}
}
and then, the OnDataReceived method (where the data is actually received):
public void OnDataReceived(IAsyncResult asyn)
{
int nbrRead = 0;
byte[] tmp = null;
try
{
nbrRead = stream.EndRead(asyn);
tmp = new byte[nbrRead];
}
catch (Exception e)
{
// *** HERE IS WHERE THE EXCEPTION IS CAUGHT ***
System.Diagnostics.Debugger.Log(0, "Bla1", e.ToString());
this.disconnect();
}
if (nbrRead > 0)
{
try
{
Array.Copy(inputBuffer, 0, tmp, 0, nbrRead);
}
catch(Exception e)
{
System.Diagnostics.Debugger.Log(0, "Bla2", e.ToString());
this.disconnect();
}
preProcessMessage(tmp);
try
{
stream.BeginRead(inputBuffer, 0, 5000, new AsyncCallback(OnDataReceived), new object());
}
catch(Exception e)
{
System.Diagnostics.Debugger.Log(0, "Bla3", e.ToString());
this.disconnect();
}
}
else
this.disconnect();
}
Right now Im sort of clueless as to what is going on... Any ideas?
UPDATE 1:
Client code for sending data:
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
Update 2
I tried to do a Flush on the outgoing stream from the client - no effect:
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
UPDATE 3: Posting more code as per request
This code is old and not the pretties in the world, I know. But it has been working very well for 5 years so =)
ClientHandler.cs (what the actual Client is using for sending etc)
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
/// <summary>
/// Summary description for connectionHandler.
/// </summary>
public class ClientHandler
{
#region Fields (17) 
string address;
Connector connector;
DataHandler dataHandler;
int id;
TCPInput input;
int interval;
string localAddress;
IPEndPoint localPoint;
int localPort;
NetworkStream outputStream;
public TTCPClientInterface parent;
int port;
tWorks.tNetworking.Protocol.Protocol protocol;
bool reconnect;
string remoteIP;
Socket socket;
public State state;
#endregion Fields 
#region Enums (1) 
public enum State {Disconnected,Connecting,Connected}
#endregion Enums 
#region Constructors (4) 
public ClientHandler(int id, TTCPClientInterface parent, Socket socket, tWorks.tNetworking.Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent, Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
state = State.Disconnected;
}
public ClientHandler(int id, TTCPClientInterface parent, Socket socket)
{
this.id=id;
this.parent = parent;
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent)
{
this.id=id;
this.parent = parent;
this.protocol = null;
changeState(State.Disconnected);
}
#endregion Constructors 
#region Delegates and Events (4) 
// Delegates (2) 
public delegate void ConnectionLostDelegate(string message);
public delegate void exceptionDelegate(Exception ex);
// Events (2) 
public event exceptionDelegate ConnectionFailed;
public event ConnectionLostDelegate ConnectionLostEvent;
#endregion Delegates and Events 
#region Methods (17) 
// Public Methods (16) 
public void connect(string address, int port, int retryInterval, bool reestablish)
{
System.Random rand = new Random();
localPort = rand.Next(40000, 60000);
IPAddress localIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]; // new IPAddress(Dns.GetHostByName(Dns.GetHostName()).AddressList[0].Address);
connect(address, port, retryInterval, reestablish, localIP.ToString(), localPort);
}
/// <summary>
/// Will connect to the address and port specified. If connection failed a new attempt will be made according to the Interval parameter.
/// If connection is lost attempts to reastablish it will be made if Reestablish is set to true.
/// </summary>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="retryInterval"></param>
/// <param name="reestablish"></param>
public void connect(string address, int port, int retryInterval, bool reestablish, string localAddress, int localPort)
{
this.reconnect = reestablish;
this.address = address;
this.port = port;
this.interval = retryInterval;
this.localAddress = localAddress;
this.localPort = localPort;
changeState(State.Connecting);
connector = new Connector(address, port, this, interval, localPoint, reestablish);
connector.Connect();
}
public void disconnect()
{
reconnect = false;
if (connector != null)
{
connector.stopConnecting();
}
setDisconnected();
}
public void dispose()
{
}
public void failedConnect(Exception e)
{
if (ConnectionFailed != null)
ConnectionFailed(e);
}
public int getID()
{
return this.id;
}
public string getIP()
{
return remoteIP;
}
public bool isConnected()
{
return this.state == State.Connected;
}
public void outDataLog(int nbrBytes)
{
parent.outDataLog(nbrBytes, id);
}
public void preProcessMessage(byte[] data)
{
//data = Crypto.Decrypt("a1s2d3", data);
if(protocol != null)
dataHandler.addData(data);
else
processMessage(data);
}
public void processMessage(byte[] data)
{
parent.processMessage(data,this);
}
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
public void setConnected(Socket thisClient)
{
socket = thisClient;
outputStream = new NetworkStream(thisClient);
input = new TCPInput(outputStream, this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
}
public void setDisconnected()
{
try
{
if (this.state == State.Connected)
{
changeState(State.Disconnected);
//socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
catch { }
if (reconnect)
this.connect(address, port, interval, true, localAddress, localPort);
}
public void stopConnect()
{
connector.stopConnecting();
changeState(State.Disconnected);
}
public override string ToString()
{
string returnString = "(D)";
if(this.state == State.Connected)
returnString = this.getIP();
return returnString;
}
// Private Methods (1) 
private void changeState(State state)
{
if (this.state == State.Connected && state == State.Disconnected)
{
if (ConnectionLostEvent != null)
ConnectionLostEvent("Uppkoppling bröts.");
}
this.state = state;
parent.connStateChange(this);
}
#endregion Methods 
}
}
This is TCPInput.cs that is listening on incoming data and forwarding that to the ClientHandler (seen above):
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
public class TCPInput
{
NetworkStream stream;
ClientHandler client;
public TCPInput(NetworkStream nS, ClientHandler client)
{
stream = nS;
this.client = client;
Thread t = new Thread(new ThreadStart(run));
t.IsBackground = true;
t.Name = "TCPInput";
t.Start();
}
public void run()
{
bool continueRead = true;
byte[] readBuffer = new byte[32768];
byte[] receivedBuffer = null;
int nbrBytesRead = 0;
int receivedBufferPos = 0;
while(continueRead)
{
try
{
nbrBytesRead = 0;
nbrBytesRead = stream.Read(readBuffer, 0, 10000);
receivedBuffer = new byte[nbrBytesRead];
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when stream.Read: " + e.ToString());
continueRead = false;
}
if(nbrBytesRead > 0)
{
try
{
Array.Copy(readBuffer, 0, receivedBuffer, receivedBufferPos, nbrBytesRead);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when Array.Copy: " + e.ToString());
continueRead = false;
}
client.preProcessMessage(receivedBuffer);
}
else
{
// *** I can break here, the nbrOfBytes read is 0 when this whole thing explodes =)
System.Diagnostics.Debug.WriteLine("TCPInput> Number of bytes read == 0! Setting continueRead = false");
continueRead = false;
}
}
client.setDisconnected();
}
}
}
The problem is in your other code, the 'client'. It closes the connection after sending all the 'packets'. You must wait until the server has received all of them. A simple approach, beyond negotiating it explicitly, is to wait for the server to close the connection.
That number ("thus sending up til 65835 bytes") is magically close to 2^16-1 (65535) -- looks like just one packet over!
(I'm assuming it's just the larger size that made things go kaboom! -- this can be tested reliably.)
I suspect there is an unsigned 16-bit variable used (in the library) where you need something with more range. Perhaps you can "empty" the internals of the library periodically or perform the operation in multiple connection? (Okay, just trying to throw out some 'quick hack' ideas :-)
So, after much testing and discussing with my partner-in-crime we found out that instead of using port 21 and taking for example port 22 - the problem goes away.
I have no idea why it behaves like this, but it does...
You post raises questions for me. Like why are you choosing well known ports for this service? I don't believe in coincidences and suspect your use of the term "partner-in-crime" may have more truth then I would care to be associated with.
Then also I am wondering why you assume a Windows bug and not one in the MyNetowrking.dll. Sure, you have been using this for five years. But it still hasn't had the level of vetting that Microsoft gives their code.

Categories