Socket.Receive() stuck - c#

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.

Related

C# client-server sockets communication in threads

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?

Unable to do server reconnection after disconnected in C# winform

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);
}
...
}

C# Socket Send and Receive on Same Machine

I am in the process of making a C# socket library that can be accessed in Visual FoxPro. Ideally, the library will contain two functions: ReceiveMessage and SendMessage. On each call, the function is supposed to {open connection -> read/write -> close connection}. I found most of what I am looking for at http://www.csharp-examples.net/socket-send-receive/; however, now I have to test (on the same machine) the modified code before compiling the dll.
I keep getting a "connection actively refused" error. While I have included all of the code below so you can see what it is doing, the issue is almost certainly in the main() at the bottom. It is my limited understanding that I cannot have two connections to the same port, but I am at a loss on how to fix it. Does anybody know sockets who can give me some direction on how to test these functions (I am new to sockets)?
namespace Sockets
{
class Sockets
{
private static void Receive(Socket socket, byte[] buffer, int offset, int size, int timeout)
{
int startTickCount = Environment.TickCount;
int received = 0; // how many bytes is already received
do
{
if (Environment.TickCount > startTickCount + timeout)
throw new Exception("Timeout.");
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)
{
// socket buffer is probably empty, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}
} while (received < size);
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
private static void Send(Socket socket, byte[] buffer, int offset, int size, int timeout)
{
int startTickCount = Environment.TickCount;
int sent = 0; // how many bytes is already sent
do
{
if (Environment.TickCount > startTickCount + timeout)
throw new Exception("Timeout.");
try
{
sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably full, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}
} while (sent < size);
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
public static string SendMessage(string ipAddress, string port, string message)
{
Socket socket = new TcpClient().Client;
try
{
socket.Connect(ipAddress, Int32.Parse(port));
Send(socket, Encoding.UTF8.GetBytes(message), 0, message.Length, 10000);
socket.Close();
return "Success";
}
catch (Exception e)
{
socket.Close();
return e.Message;
}
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
public static string ReceiveMessage(string ipAddress, string port, int bufferSize = 1024)
{
Socket socket = new TcpClient().Client;
try
{
socket.Connect(ipAddress, Int32.Parse(port));
byte[] buffer = new byte[bufferSize];
Receive(socket, buffer, 0, buffer.Length, 10000);
socket.Close();
return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
}
catch (Exception e)
{
socket.Close();
return e.Message;
}
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
}
}
class Program
{
static void Main(string[] args)
{
new Thread(delegate() {var test = Sockets.Sockets.SendMessage("localhost", "60010", "abcdefg");}).Start();
new Thread(delegate() {Console.WriteLine(Sockets.Sockets.ReceiveMessage("localhost", "60010"));}).Start();
var waitForEnter = Console.ReadLine();
}
}
With a tilda (~) as the trailing character, here is the functional receive function (old code is commented):
public static string ReceiveMessage(string ipAddress, string port, int bufferSize = 1024)
{
try
{
TcpListener serverSocket = new TcpListener(new System.Net.IPAddress(IPAddress.Parse(ipAddress).GetAddressBytes()), Int32.Parse(port));
serverSocket.Start();
TcpClient clientSocket = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
int bytesRead;
string buffer = "";
byte[] bytesFrom = new byte[bufferSize];
while (true)
{
bytesRead = networkStream.Read(bytesFrom, 0, bytesFrom.Length);
string incoming = System.Text.Encoding.ASCII.GetString(bytesFrom, 0, bytesRead);
buffer = buffer + incoming;
while (buffer.Contains("~"))
{
string msg = buffer.Substring(0, buffer.IndexOf("~"));
// buffer = buffer.Remove(0, msg.Length + 3);
return msg;
}
}
//var socket = new TcpListener(new IPAddress(IPAddress.Parse(ipAddress).GetAddressBytes()), Int32.Parse(port));
//try
//{
//byte[] buffer = new byte[bufferSize];
// Receive(socket, buffer, 0, buffer.Length, 10000);
// socket.Close();
// return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
//}
//catch (Exception e)
//{
// socket.Close();
// return e.Message;
//}
}
catch (Exception e)
{
return e.Message;
}
}

Determine end of message in socket stream

I have a project with a server and a client using asynchronous socket connections.
I want to transmit an object from server to client. Unfortunately I have the problem, that sometimes the object isn't fully transmitted in one go. Therefore I need a way to determine when an object was fully transmitted. So I added a four-byte-head to the data transmitted to tell, how long the stream will be.
Server
private void Send(Socket handler, Packet packet)
{
byte[] byteData = ByteHelper.Serialize(packet).Data;
byte[] byteDataLength = BitConverter.GetBytes(byteData.Length);
byte[] transmissionData = new byte[byteDataLength.Length + byteData.Length];
byteDataLength.CopyTo(transmissionData, 0);
byteData.CopyTo(transmissionData, byteDataLength.Length);
if (debug)
{
Status = "Sending "+packet.Type+"-packet to client.";
}
try
{
handler.BeginSend(transmissionData, 0, transmissionData.Length, 0, new AsyncCallback(SendCallback), handler);
}
catch (Exception ex)
{
Status = "[EXCEPTION]" + ex.Message.ToString();
}
}
The client receives the stream and evaluates the first four bytes to create a StateObject which has the right size. But I have the feeling that this is not really a good way to solve my problem. Is there a better way to do this?
Client
private void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
try
{
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
do
{
state = AdjustState(state);
if (state != null)
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
}
else
{
receiveDone.Set();
}
}
while (state != null && state.tempBuffer.Length >= state.bufferSize);
if (state != null)
{
client.BeginReceive(state.tempBuffer, 0, state.tempBuffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
catch (Exception ex)
{
MessageBox.Show("ReceiveCallback: " + ex.ToString(), "Client-Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static StateObject AdjustState(StateObject state)
{
StateObject tempState = state;
if (tempState.tempBuffer.Length >= 4)
{
byte[] sizeBytes = tempState.tempBuffer.Take(4).ToArray();
int bufferSize = BitConverter.ToInt32(sizeBytes, 0);
if (bufferSize == 0)
{
return null;
}
byte[] temp = tempState.tempBuffer.Skip(4).ToArray();
Socket tempSocket = tempState.workSocket;
tempState = new StateObject(bufferSize);
tempState.BufferSet();
if (temp.Length >= bufferSize)
{
tempState.buffer = temp.Take(bufferSize).ToArray();
tempState.tempBuffer = temp.Skip(bufferSize).ToArray();
}
tempState.workSocket = tempSocket;
}
return tempState;
}
Solution
Thanks to usr I've changed the bytesRead-Part in the ReceiveCallbackCode of the client to this. It seems to work now.
if (bytesRead > 0)
{
if (!state.bufferSet)
{
state = AdjustState(state);
client.BeginReceive(state.buffer, 0, state.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
else
{
client.BeginReceive(state.buffer, state.buffer.Length, state.bufferSize - state.buffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
You are not making use of the return value from EndReceive (bytesRead). It signals how many bytes were received.
And in case bytesRead == 0 you just do nothing which is probably not a proper response to the connection having ended.
And then, there is this unsynchronized busy-loop:
while (state != null && state.tempBuffer.Length >= state.bufferSize);
That's going to burn one CPU core for each client connection. Must solve this differently.

Client-Server-Communication between C#-Java

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!

Categories

Resources