I'm doing an application which require me as a client side to connect to a server and receive data from the server. I will need to do re-connection when the connection is disconnected. Below is my code:
public enum MySocketState
{
Disconnected = 0,
Connecting,
Connected
}
private Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private byte[] _recieveBuffer = new byte[128];
void DataProcess()
{
try
{
if (_serverSocket == null || sockState == MySocketState.Disconnected)
{
Console.WriteLine("Trying to connect...");
SetupServer();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void SetupServer()
{
try
{
_serverSocket.Connect("192.168.1.11", 1000);
}
catch (SocketException ex)
{
Console.WriteLine(ex.Message);
}
sockState = MySocketState.Connected;
Console.WriteLine("Server connected...");
_serverSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
if (_serverSocket == null)
_serverSocket = (Socket)AR.AsyncState;
int recieved = _serverSocket.EndReceive(AR);
if (recieved <= 0)
{
CloseSocket();
return;
}
byte[] recData = new byte[recieved];
Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved);
string strData = ASCIIEncoding.ASCII.GetString(recData);
Console.WriteLine(strData);
//Process the data stored in recData
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
CloseSocket();
}
finally
{
try
{
//Start receiving again
if (_serverSocket != null)
_serverSocket.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
catch (Exception ex2)
{ }
}
}
public void CloseSocket()
{
try
{
if (_serverSocket != null)
{
if (_serverSocket.Connected)
_serverSocket.Shutdown(SocketShutdown.Both);
_serverSocket.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
_serverSocket = null;
sockState = MySocketState.Disconnected;
}
private void timer1_Tick(object sender, EventArgs e)
{
DataProcess();
}
I'm using a timer (timer1_tick) to always detect whether or not the server is connected.
But after it disconnected with the server, it cannot be reconnected back and below is the error message on line _serverSocket.Connect("192.168.1.11", 1000):
A first chance exception of type 'System.NullReferenceException' occurred in fform.exe
System.NullReferenceException: Object reference not set to an instance of an object.
at fform.Form1.SetupServer() in c:\Work\Project 2015\Form1.cs:line 143
at fform.Form1.DataProcess() in c:\Work\Project 2015\Form1.cs:line 79
Do you guys know how come it cannot be connect back?
Probably it's because you set _serverSocket to null after you CloseSocket() and did not create a new Socket instance when you try to reconnect.
public void CloseSocket()
{
...
_serverSocket = null;
...
}
Look at the line number in the error message
at fform.Form1.SetupServer() in c:\Work\Project 2015\Form1.cs:line
143 at fform.Form1.DataProcess() in c:\Work\Project
2015\Form1.cs:line 79
You should probably do the following when you reconnect:
private void SetupServer()
{
try
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //Added
_serverSocket.Connect("192.168.1.11", 1000);
}
...
}
Related
I have created these applications. One is server socket which consists of main thread responsible for creating client/server connection and creating other threads:
thread for producing messages
thread for listening for received messages from client
thread to send produced messages by server
If there is connection disrupted server frees any resources and waits for new connections in a loop.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class SynchronousSocketListener {
private Socket handler; //socket handlet
private byte[] bytes; // Data buffer for incoming data.
private List < String > messagesToSend;
private Mutex messagesToSendMutex;
public SynchronousSocketListener() {
messagesToSendMutex = new Mutex();
try {
messagesToSendMutex.WaitOne();
messagesToSend = new List < String > ();
} finally {
messagesToSendMutex.ReleaseMutex();
}
bytes = new Byte[1024];
handler = null;
}
private void addMessageToQueue(string message) {
try {
messagesToSendMutex.WaitOne();
messagesToSend.Add(message);
} finally {
messagesToSendMutex.ReleaseMutex();
}
}
private string readMessageFromQueue() {
string ret = null;
try {
messagesToSendMutex.WaitOne();
if (messagesToSend.Count > 0)
ret = messagesToSend[0];
} finally {
messagesToSendMutex.ReleaseMutex();
}
return ret;
}
private void removeMessageFromQueue(string messageToRemove) {
string ret = null;
try {
messagesToSendMutex.WaitOne();
if (messagesToSend.Count > 0)
messagesToSend.Remove(messageToRemove);
} finally {
messagesToSendMutex.ReleaseMutex();
}
}
private void threadForGeneratingMessages() {
while (true) {
addMessageToQueue(Console.ReadLine());
}
}
private void sendingThread(CancellationToken ct) {
while (true) {
try {
if (ct.IsCancellationRequested) {
// Clean up here, then...
ct.ThrowIfCancellationRequested();
Console.WriteLine("Task sending is cancelled");
return;
}
} catch (System.OperationCanceledException ex) {
Console.WriteLine("System.OperationCanceledException");
return;
}
if (messagesToSend.Count <= 0) {
Console.WriteLine("No more messages to send");
Thread.Sleep(5000);
continue;
}
Console.WriteLine("Server is going to write some data for client");
//send pending messages to client
string dataToSendNow = messagesToSend[0];
byte[] msg = Encoding.ASCII.GetBytes(dataToSendNow + "<EOF>");
try {
// Send the data through the socket.
int bytesSent = handler.Send(msg);
messagesToSend.Remove(dataToSendNow);
Console.WriteLine("Server send data");
} catch (SocketException ex) {
Console.WriteLine(ex.ToString());
Console.WriteLine("returning from sendingThread sockEx");
return;
} catch (ObjectDisposedException ex) {
Console.WriteLine(ex.ToString());
//socketError = true;
Console.WriteLine("returning from sendingThread objDisEx");
return;
}
Thread.Sleep(100);
}
}
private void receivingThread(CancellationToken ct) {
while (true) {
try {
if (ct.IsCancellationRequested) {
// Clean up here, then...
ct.ThrowIfCancellationRequested();
Console.WriteLine("Task receiving is cancelled");
return;
}
} catch (System.OperationCanceledException ex) {
Console.WriteLine("System.OperationCanceledException");
return;
}
Console.WriteLine("Server is waiting for a new message to arrive: ");
try {
if (!handler.Connected) throw new SocketException();
//handler.Send(new byte[] { 0 });
int bytesRec = handler.Receive(bytes);
string receivedData = Encoding.ASCII.GetString(bytes, 0, bytesRec);
Console.WriteLine("Server has received message = {0}",
receivedData);
/*
//do some stuff with the message
.
.
.
*/
} catch (SocketException ex) {
Console.WriteLine(ex.ToString());
//socketError = true;
return;
} catch (ObjectDisposedException ex) {
Console.WriteLine(ex.ToString());
//socketError = true;
return;
}
}
}
public void StartListening() {
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
while (true) {
// Create a TCP/IP socket.
// Bind the socket to the local endpoint and
// listen for incoming connections.
Socket listener = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine("New connection can be made");
try {
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11100);
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
Console.WriteLine("Waiting for a connection...");
// Program is suspended while waiting for an incoming connection.
handler = listener.Accept();
Console.WriteLine("New connection is made");
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
//when new connection is made create new thread for sending data through socket
var task_send = Task.Run(() => {
sendingThread(ct);
}, tokenSource2.Token);
var tokenSource3 = new CancellationTokenSource();
CancellationToken ct3 = tokenSource3.Token;
//when new connection is made create new thread for receiving data through socket
var task = Task.Run(() => {
receivingThread(ct3);
}, tokenSource3.Token);
while (true) {
if (task.IsCompleted || task_send.IsCompleted) { //activelly oolling the field to find out, wether threads has been cancelled/returned
Console.WriteLine("some tasks is Completed");
tokenSource2.Cancel();
tokenSource3.Cancel();
handler.Shutdown(SocketShutdown.Both);
handler.Close();
break; //breaking from polling loop to prepare for a new connection
}
}
} catch (SocketException se) {
Console.WriteLine(se.ToString());
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
listener.Dispose(); //disposing listener so that new one can be created
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static int Main(String[] args) {
SynchronousSocketListener synSocList = new SynchronousSocketListener();
var task_generateMsg = Task.Run(
(synSocList.threadForGeneratingMessages));
synSocList.StartListening();
return 0;
}
}
client's app structure is basically the same as server's with exception, that it is actively trying to connect to server, if connection has been disrupted:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class SynchronousSocketClient {
private Socket sender; //socket
private byte[] bytes; // Data buffer for incoming data.
private List < String > messagesToSend;
private Mutex messagesToSendMutex;
public SynchronousSocketClient() {
messagesToSendMutex = new Mutex();
try {
messagesToSendMutex.WaitOne();
messagesToSend = new List < String > ();
} finally {
messagesToSendMutex.ReleaseMutex();
}
bytes = new Byte[1024];
sender = null;
}
private void addMessageToQueue(string message) {
try {
messagesToSendMutex.WaitOne();
messagesToSend.Add(message);
} finally {
messagesToSendMutex.ReleaseMutex();
}
}
private string readMessageFromQueue() {
string ret = null;
try {
messagesToSendMutex.WaitOne();
if (messagesToSend.Count > 0)
ret = messagesToSend[0];
} finally {
messagesToSendMutex.ReleaseMutex();
}
return ret;
}
private void removeMessageFromQueue(string messageToRemove) {
string ret = null;
try {
messagesToSendMutex.WaitOne();
if (messagesToSend.Count > 0)
messagesToSend.Remove(messageToRemove);
} finally {
messagesToSendMutex.ReleaseMutex();
}
}
private void threadForGeneratingMessages() {
while (true) {
addMessageToQueue(Console.ReadLine());
}
}
private void sendingThread(CancellationToken ct) {
while (true) {
try {
if (ct.IsCancellationRequested) {
// Clean up here, then...
ct.ThrowIfCancellationRequested();
Console.WriteLine("Task sending is cancelled");
return;
}
} catch (System.OperationCanceledException ex) {
Console.WriteLine("System.OperationCanceledException");
return;
}
if (messagesToSend.Count <= 0) {
Console.WriteLine("No more messages to send");
Thread.Sleep(5000);
continue;
}
Console.WriteLine("Client is going to write some data for client");
//send pending messages to client
string dataToSendNow = messagesToSend[0];
byte[] msg = Encoding.ASCII.GetBytes(dataToSendNow + "<EOF>");
try {
// Send the data through the socket.
int bytesSent = sender.Send(msg);
messagesToSend.Remove(dataToSendNow);
Console.WriteLine("Client send data");
} catch (SocketException ex) {
Console.WriteLine(ex.ToString());
Console.WriteLine("returning from sendingThread sockEx");
return;
} catch (ObjectDisposedException ex) {
Console.WriteLine(ex.ToString());
//socketError = true;
Console.WriteLine("returning from sendingThread objDisEx");
return;
}
}
}
private void receivingThread(CancellationToken ct) {
while (true) {
try {
if (ct.IsCancellationRequested) {
// Clean up here, then...
ct.ThrowIfCancellationRequested();
Console.WriteLine("Task receiving is cancelled");
return;
}
} catch (System.OperationCanceledException ex) {
Console.WriteLine("System.OperationCanceledException");
return;
}
Console.WriteLine("Client is waiting for a new message to arrive: ");
try {
if (!sender.Connected) throw new SocketException();
//sender.Send(new byte[] { 0 });
int bytesRec = sender.Receive(bytes);
string receivedData = Encoding.ASCII.GetString(bytes, 0, bytesRec);
Console.WriteLine("Client has received message = {0}",
receivedData);
/*
//do some stuff with the message
.
.
.
*/
} catch (SocketException ex) {
Console.WriteLine(ex.ToString());
//socketError = true;
return;
} catch (ObjectDisposedException ex) {
Console.WriteLine(ex.ToString());
//socketError = true;
return;
}
}
}
private void sendingThread() {
while (true) {
Console.WriteLine("Write some data for server");
string line = Console.ReadLine();
byte[] msg = Encoding.ASCII.GetBytes(line + "<EOF>");
try {
// Send the data through the socket.
int bytesSent = sender.Send(msg);
Console.WriteLine("data are send");
// Receive the response from the remote device.
} catch (SocketException ex) {
Console.WriteLine(ex.ToString());
socketError = false;
return;
}
Thread.Sleep(100);
}
}
volatile private bool socketError = false;
private void receivingThread() {
while (true) {
Console.WriteLine("receiving:");
try {
if (!sender.Connected) throw new SocketException();
sender.Send(new byte[] {
0
});
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
} catch (SocketException ex) {
Console.WriteLine(ex.ToString());
socketError = true;
return;
}
}
}
public void StartClient() {
// Data buffer for incoming data.
while (true) {
// Connect to a remote device.
try {
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11100);
// Create a TCP/IP socket.
sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try {
sender.Connect(remoteEP);
Console.WriteLine("Client has made connection to the server");
/*
try
{
task_send.Wait();
}
catch (AggregateException ae)
{
Console.WriteLine(ae.ToString());
foreach (var ex in ae.InnerExceptions)
{
throw ex;
}
}
*/
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
//when new connection is made create new thread for sending data through socket
var task_send = Task.Run(() => {
sendingThread(ct);
}, tokenSource2.Token);
var tokenSource3 = new CancellationTokenSource();
CancellationToken ct3 = tokenSource3.Token;
//when new connection is made create new thread for receiving data through socket
var task = Task.Run(() => {
receivingThread(ct3);
}, tokenSource3.Token);
while (true) {
if (task.IsCompleted || task_send.IsCompleted) { //activelly oolling the field to find out, wether threads has been cancelled/returned
Console.WriteLine("some tasks is Completed");
tokenSource2.Cancel();
tokenSource3.Cancel();
sender.Shutdown(SocketShutdown.Both);
sender.Close();
break; //breaking from polling loop to prepare for a new connection
}
}
/*
var task_send = Task.Run(
(sendingThread));
var task = Task.Run(
(receivingThread));
*/
/*
try
{
task.Wait();
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
{
throw ex;
}
}*/
/*
bool task_receiving_res = false;
//int timeout = 60000;
Task<bool> task_receiving = new Task<bool>(() => receivingThread());
task_receiving.Start();
Console.WriteLine("here0");
if (await Task.WhenAny(task_receiving, Task.Delay(Timeout.Infinite)) == task_receiving)
{
Console.WriteLine("here-0");
// task completed within timeout
task_receiving_res = task_receiving.Result;
}
else
{
throw new TimeoutException();
}
Console.WriteLine("here");
bool task_sending_res = false;
//int timeout = 60000;
Task<bool> task_sending = new Task<bool>(() => sendingThread());
task_sending.Start();
if (await Task.WhenAny(task_sending, Task.Delay(Timeout.Infinite)) == task_sending)
{
// task completed within timeout
task_sending_res = task_sending.Result;
}
else
{
throw new TimeoutException();
}
*/
/*
Console.WriteLine("here1");
while (true) {
if (socketError) {
/*task.Dispose();
task_send.Dispose();
*/
/*
socketError = false;
throw new Exception("restart connection");
}
}*/
/*
while (true)
{
*/
/*Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());*/
/*
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes("This is a test<EOF>");
// Send the data through the socket.
int bytesSent = sender.Send(msg);
*/
// Receive the response from the remote device.
/*int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
*/
/*
bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
*/
/*
Thread.Sleep(5000);
}*/
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
} catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
} catch (SocketException se) {
Console.WriteLine("SocketException : {0}", se.ToString());
} catch (Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Thread.Sleep(5000);
}
}
public static int Main(String[] args) {
SynchronousSocketClient sc = new SynchronousSocketClient();
var task_generateMsg = Task.Run(
(sc.threadForGeneratingMessages));
sc.StartClient();
return 0;
}
}
How could these code be written do be more efficient? Is this safe, or are there any problems with these code (besides efficiency)?
Edit:
I have a problem with the code:
sometimes receivingThread is looping without halting at handler/sender.Receive() function, it seems to read 0 bytes even though other side does not send anything. How can this be corrected?
I have a server in C that send message to unity. In Unity, I can receive data once, but when the server sends a new message, unity receives nothing.
For example: Unity can connect to server, receive the first message that said "move right" and move the camera of Unity to the right but then if the server send "move left" or anything else unity is block in the function receive which calls BeginReceive:
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
Code of my server:
void connectToUnity() {
SOCKADDR_IN sin;
WSAStartup(MAKEWORD(2, 0), &WSAData);
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
sin.sin_family = AF_INET;
sin.sin_port = htons(53660);
bind(sock, (SOCKADDR*)&sin, sizeof(sin));
listen(sock, 0);
printf("Connexion to unity\n");
}
void sendDataToUnity(const char * mouvement) {
SOCKET csock;
while (1)
{
int sinsize = sizeof(csin);
if ((csock = accept(sock, (SOCKADDR*)&csin, &sinsize)) != INVALID_SOCKET)
{
send(csock, mouvement, 14, 0);
printf("Donnees envoyees \n");
return;
}
else {
printf("Rien n'a ete envoye");
}
}
}
Code in Unity:
public bool ConnectToServer(string hostAdd, int port)
{
//connect the socket to the server
try
{
//create end point to connect
conn = new IPEndPoint(IPAddress.Parse(hostAdd), port);
//connect to server
clientSocket.BeginConnect(conn, new AsyncCallback(ConnectCallback), clientSocket);
socketReady = true;
connectDone.WaitOne();
Debug.Log("Client socket ready: " + socketReady);
// Receive the response from the remote device.
Receive(clientSocket);
//receiveDone.WaitOne();
}
catch (Exception ex)
{
Debug.Log("socket error: " + ex.Message);
}
return socketReady;
}
//async call to connect
static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket
Socket client = (Socket)ar.AsyncState;
// Complete the connection
client.EndConnect(ar);
Debug.Log("Client Socket connected to: " + client.RemoteEndPoint);
connectDone.Set();
}
catch (Exception e)
{
Debug.Log("Error connecting: " + e);
}
}
private static void Receive(Socket client)
{
try
{
Debug.Log("Try to receive");
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Debug.Log(e);
}
}
static void ReceiveCallback(IAsyncResult ar)
{
try
{
//Read data from the remote device.
Debug.Log("receive callback");
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
Debug.Log("Il y a une réponse");
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
response = state.sb.ToString();
Debug.Log(response);
//client.Shutdown(SocketShutdown.Both);
}
else
{
if(state.sb.Length > 1)
{
response = state.sb.ToString();
Debug.Log(response);
}
}
}
catch (Exception ex)
{
Debug.Log("Error: " + ex.Message);
}
}
The function receive is called once in the function ConnectToServer, then I tried to call again in the update like this:
void Update()
{
if (response.Contains("right"))
{
Debug.Log("Move to the right ");
float x = Camera.main.transform.localEulerAngles.x;
float y = Camera.main.transform.localEulerAngles.y;
DeplacementCamera.moveRight(x, y);
response = "";
Receive(clientSocket);
}
}
I have already see this post but without success or maybe I tried it in the wrong way:
Why does BeginReceive() not return for more than one read?
Edit: In the function ReceiveCallback the else is never reached.
you may change your method
private void SetupReceiveCallback(Socket sock)
{
try
{
DataBuffer = new byte[BufferSize];
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
sock.BeginReceive(DataBuffer, 0, DataBuffer.Length, SocketFlags.None, recieveData, _socket);
}
catch (Exception E)
{
}
}
private void OnRecievedData(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
if (sock.Connected)
{
int nBytesRec = sock.EndReceive(ar);
if (nBytesRec > 0)
{
string Data = Encoding.UTF8.GetString(DataBuffer);
if (Data.Length != 4)
{
string JsonString = Data;
if (!string.IsNullOrEmpty(JsonString))
{
try
{
//Add you code processing here
}
catch (Exception ex)
{
}
}
BufferSize = 4;
}
else
{
BufferSize = BitConverter.ToInt32(DataBuffer, 0);
}
}
SetupReceiveCallback(sock);
}
else
// on not connected to socket
}
catch (Exception E)
{
}
}
public bool Connect(string IP, int Port)
{
try
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//if (IsValidIP(IP))
//{
// IPEndPoint epServer = new IPEndPoint(IPAddress.Parse(IP), Port);
// _socket.Connect(epServer);
//}
//else
//{
// _socket.Connect(IP, Port);
//}
//SetupReceiveCallback(_socket);
}
catch(Exception ex)
{
}
return false;
}
I'm doing an application which require me as a client side to connect to a server and receive data from the server. I will need to do re-connection when the connection is disconnected. Below is my code:
public enum MySocketState
{
Disconnected = 0,
Connecting,
Connected
}
public Socket theDevSock = null;
public MySocketState sockState = MySocketState.Disconnected;
void DataProcess()
{
try
{
if (theDevSock == null || sockState == MySocketState.Disconnected)
{
Console.WriteLine("Trying to connect...");
StartConnect();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public bool StartConnect(/*AsyncCallback requestCallback*/)
{
Socket theSocket = null;
try
{
Console.WriteLine("Start connect to server...");
theSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
theSocket.BeginConnect("192.168.1.10", 1000, ConnectCallback, theSocket);
sockState = MySocketState.Connecting;
return true;
}
catch (Exception ex)
{
Console.WriteLine("#### Unable to connect to server...");
}
CloseSocket();
return false;
}
void ConnectCallback(IAsyncResult ar)
{
try
{
theDevSock = (Socket)ar.AsyncState;
if (theDevSock != null)
{
if (theDevSock.Connected)
{
sockState = MySocketState.Connected;
Console.WriteLine("Server is connected...");
theDevSock.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, this.ReceiveCallback, theDevSock);
return;
}
}
Console.WriteLine("Failed to connect to server...");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
CloseSocket();
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
if (theDevSock == null)
theDevSock = (Socket)AR.AsyncState;
int recieved = theDevSock.EndReceive(AR); // Error occur in this line after re-connection.
if (recieved <= 0)
{
CloseSocket();
return;
}
byte[] recData = new byte[recieved];
Buffer.BlockCopy(_recieveBuffer, 0, recData, 0, recieved);
string strData = ASCIIEncoding.ASCII.GetString(recData);
Console.WriteLine(strData);
//Process the data stored in recData
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
CloseSocket();
}
finally
{
try
{
//Start receiving again
if (theDevSock != null)
theDevSock.BeginReceive(_recieveBuffer, 0, _recieveBuffer.Length, SocketFlags.None, ReceiveCallback, theDevSock);
}
catch (Exception ex2)
{ }
}
}
public void CloseSocket()
{
try
{
if (theDevSock != null)
{
if (theDevSock.Connected)
theDevSock.Shutdown(SocketShutdown.Both);
theDevSock.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
theDevSock = null;
sockState = MySocketState.Disconnected;
}
private void timer1_Tick(object sender, EventArgs e)
{
DataProcess();
}
}
I'm using a timer (timer1_tick) to always detect whether or not the server is connected.
The coding have no problem in reconnecting back to the server if the connection has been disconnected. The problem is after reconnection and when it receive the first data from the server, an error occur at line int recieved = theDevSock.EndReceive(AR). The error message is as below:
A first chance exception of type 'System.ArgumentException' occurred in System.dll
A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll
System.ArgumentException: The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
Parameter name: asyncResult
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult, SocketError& errorCode)
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at fform.ReceiveCallback(IAsyncResult AR) in c:\Work\Project 2015\Form1.cs:line 163
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult, SocketError& errorCode)
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at fform.Form1.ReceiveCallback(IAsyncResult AR) in c:\Work\Project 2015\Form1.cs:line 163
Why is it the IAsyncResult object was not returned?
According to MSDN
The asynchronous BeginConnect operation must be completed by calling
the EndConnect method. Typically, the method is invoked by the
requestCallback delegate.
In your
void ConnectCallback(IAsyncResult ar)
You should put a line for EndConnect before begin receive
void ConnectCallback(IAsyncResult ar)
{
try
{
theDevSock = (Socket)ar.AsyncState;
theDevSock.EndConnect(ar);
//blabla
}
}
Else the socket which is connected and which receives the data might be different
Note: I would prefer not to put Socket theSocket for calling BeginConnect in the class scope rather than method scope, and then pass it to theDevSock since they are the same socket ultimately.
I'm practicing my C# after having missed out on it in about two years and writing a client for a server. Anyways, the problem is that Socket.Receive() seems to be stuck (my loop doesn't actually get through, tested it).. Here's my call in Program.cs: byte[] buffer = new byte[7];
hSocket.Receive(buffer, 0, buffer.Length, 500);And here's the snippet of my APISocket.cs public bool Connect(string ServerIP, int ServerPort, int Timeout)
{
TimeoutObject.Reset();
SocketException = null;
try
{
Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint IPEndPoint = new IPEndPoint(IPAddress.Parse(ServerIP), ServerPort);
object state = new object();
Socket.BeginConnect(IPEndPoint, new AsyncCallback(CallBackMethod), state);
if (TimeoutObject.WaitOne(Timeout, false))
{
if (IsConnected)
return true;
else
return false;
}
else
{
return false;
}
}
catch (Exception Ex)
{
SocketException = Ex;
}
return false;
}
private void CallBackMethod(IAsyncResult AsyncResult)
{
try
{
IsConnected = false;
if (Socket.Connected)
{
IsConnected = true;
}
}
catch (Exception Ex)
{
IsConnected = false;
SocketException = Ex;
}
finally
{
TimeoutObject.Set();
}
}
public void Receive(byte[] buffer, int offset, int size, int timeout)
{
SocketException = null;
int startTick = Environment.TickCount;
int received = 0;
do
{
if (Environment.TickCount > startTick + timeout)
{
SocketException = new Exception("Timeout.");
return;
}
try
{
received += Socket.Receive(buffer, offset + received, size - received, SocketFlags.None);
}
catch (SocketException Ex)
{
if (Ex.SocketErrorCode == SocketError.WouldBlock ||
Ex.SocketErrorCode == SocketError.IOPending ||
Ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
Thread.Sleep(30);
}
else
{
SocketException = Ex;
return;
}
}
} while (received < size);
}
I have no idea where I'm going wrong, any help would be appreciated..
Socket.Receive() is a blocking call. If there is no data available it will block until there is data available to read. See MSDN.
If no data is available for reading, the Receive method will block until data is available, unless a time-out value was set by using Socket.ReceiveTimeout. If the time-out value was exceeded, the Receive call will throw a SocketException.
first: I hope my english is not so bad (maybe it's gerglish; german grammer with english vocabularies)
I'm writing an server in java for android which communicates with an client written in c# running on WindowsCE 5. The big problem is that sometimes especially or maybe only if the network is unstable my java server still blocks in the accept-Method also when the client is sending data. I simulated the unstable network by switch off and on my virtual router over which both devices communicate. I also could recognize that the c#-program hangs in the write- or read-method or throws an IOException also when the network is switched on and my server is hearing on the expected port.
Here is the source code of the client:
Some information:
1. It is sending 10000 messages only for testing
static void Main(string[] args)
{
string server = ...;
int port = 12000;
String outputStr = "";
NetworkStream stream = null;
for (int i = 0; i < 10000; i++)
{
TcpClient client = null;
String messageToSend = ...
try
{
IPAddress ipAddress = IPAddress.Parse(server);
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, port);
AutoResetEvent connectDone = new AutoResetEvent(false);
client = new TcpClient();
client.Client.BeginConnect(ipEndPoint,
new AsyncCallback(
delegate(IAsyncResult ar)
{
try
{
client.Client.EndConnect(ar);
connectDone.Set();
}
catch (Exception ex)
{}
}
), client.Client);
if (!connectDone.WaitOne(5000, false))
{
outputStr = "NOTConnected";
}
Byte[] data = System.Text.Encoding.UTF8.GetBytes(messageToSend);
stream = client.GetStream();
try
{
stream.Write(data, 0, data.Length);
data = new Byte[2048];
int bytes = stream.Read(data, 0, data.Length);
string responseData = System.Text.Encoding.UTF8.GetString(data, 0, bytes);
outputStr = responseData;
}
catch (IOException ex)
{
outputStr = ex.Message;
}
}
}
catch (SocketException ex)
{
outputStr = ex.Message;
}
catch (Exception ex)
{
outputStr = ex.Message;
}
finally
{
if (stream != null) stream.Close();
}
System.Threading.Thread.Sleep(200);
}
Console.WriteLine("\n Press Enter to continue... " + outputStr);
Console.Read();
}
And my source code of the server:
Some information. My servlet normally is an inner class and first checks if the devices is connected to a router. If it is it starting to here on a port. If not it goes to wait mode (see _sendToSleep()). If devices is reconnected the activity can wakes it up by notify. If it looses again the connection the Activity will cause a SocketException by closing the socket so the servlet can leave the accept-method.
public class ServletThread extends Thread {
private int port;
private ServerSocket serverSocket;
private Socket socket;
public ServletThread(int port) throws IOException {
super();
this.port = port;
serverSocket = new ServerSocket(port);
}
private void checkConnectivity(BufferedWriter out) {
try {
String outgoingMsg = "connected";
out.write(outgoingMsg);
out.flush();
} catch (IOException e) {
Log.e(TAG, "connectivity exception " + e.getMessage());
}
}
private void readStream(Scanner scanner) throws IOException {
String str = "";
while (scanner.hasNext()) {
str += scanner.nextLine();
}
final String fTicket = str;
runOnUiThread(new Runnable() {
#Override
public void run() {
if (MyActivity.this.isFinishing()) {
return;
}
// do something
}
});
}
private void _sendToSleep() {
try {
synchronized (this) {
this.wait();
}
} catch (InterruptedException e) {
this.interrupt();
}
}
#Override
public void interrupt() {
super.interrupt();
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
Log.e(TAG, ""+e.getMessage());
}
}
}
#Override
public void run() {
try {
serverSocket = new ServerSocket(port);
} catch (IOException ex) {
Log.e(TAG,""+ex.getMessage());
}
while (!isInterrupted()) {
if (connectionState != NetworkInfo.State.CONNECTED) {
_sendToSleep();
} else {
BufferedWriter out = null;
Scanner scanner = null;
try {
socket = serverSocket.accept();
out = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
scanner = new Scanner(socket.getInputStream());
checkConnectivity(out);
readStream(scanner);
} catch (IOException ex) {
Log.e(TAG, ex.getMessage() + "");
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "exception on close socket " + e.getMessage());
}
}
if (scanner != null) {
scanner.close();
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
Log.e(TAG, ""+e.getMessage());
}
}
}
}
}
}
}
After isolating the bug, i did some changes:
c# instead of stream = client.getStream
(using Stream = client.getStream()) {
...
stream.WriteTimeout = 1000;
stream.ReadTimeout = 1000;
...
}
in java changes in the _sendToSleep()
private void _sendToSleep() {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
Log.e(TAG, "failed to close serverSocket " + e.getMessage());
}
}
try {
synchronized (this) {
this.wait();
}
} catch (InterruptedException e) {
this.interrupt();
}
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
Log.e(TAG, "failed to open serversocket " + e.getMessage());
}
}
It became better, means, I could not reproduce the problem.
My questions:
Why did it the client hang? (maybe a synchronisation problem on servlet-side and client between socketserver and wlan-adapter after reconnecting several times, so that the servlet cannot get any data???)
And do my changes solve the problem.
Thanking you in anticipation!