Creating a Chat With Server Socket Channel - sockets

I'm creating a chat with ServerSocketChannel and maintain communication between Clients - Server.
The server receives a message from the client and broadcasts to every client.
I tried to send a message to the server and everything was fine, but when I try to send a message to the client from the server the message doesn't get there. It only delivers when I close the socket. (It's like it was buffered)
Here's my code for the server:
static public void main( String args[] ) throws Exception {
// Parse port from command line
int port = Integer.parseInt( args[0] );
try {
// Instead of creating a ServerSocket, create a ServerSocketChannel
ServerSocketChannel ssc = ServerSocketChannel.open();
// Set it to non-blocking, so we can use select
ssc.configureBlocking( false );
// Get the Socket connected to this channel, and bind it to the
// listening port
ServerSocket ss = ssc.socket();
InetSocketAddress isa = new InetSocketAddress( port );
ss.bind( isa );
// Create a new Selector for selecting
Selector selector = Selector.open();
// Register the ServerSocketChannel, so we can listen for incoming
// connections
ssc.register( selector, SelectionKey.OP_ACCEPT );
System.out.println( "Listening on port "+port );
while (true) {
// See if we've had any activity -- either an incoming connection,
// or incoming data on an existing connection
int num = selector.select();
// If we don't have any activity, loop around and wait again
if (num == 0) {
continue;
}
// Get the keys corresponding to the activity that has been
// detected, and process them one by one
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
// Get a key representing one of bits of I/O activity
SelectionKey key = it.next();
// What kind of activity is it?
if ((key.readyOps() & SelectionKey.OP_ACCEPT) ==
SelectionKey.OP_ACCEPT) {
// It's an incoming connection. Register this socket with
// the Selector so we can listen for input on it
Socket s = ss.accept();
clientList.add(new Client(s));
System.out.println( "Got connection from "+s );
// Make sure to make it non-blocking, so we can use a selector
// on it.
SocketChannel sc = s.getChannel();
sc.configureBlocking( false );
// Register it with the selector, for reading
sc.register( selector, SelectionKey.OP_READ );
} else if ((key.readyOps() & SelectionKey.OP_READ) ==
SelectionKey.OP_READ) {
SocketChannel sc = null;
try {
// It's incoming data on a connection -- process it
sc = (SocketChannel)key.channel();
boolean ok = processInput( sc );
/* HERE, TRYING TO SEND A TEST MESSAGE BACK */
ByteBuffer bf = ByteBuffer.allocate(48);
bf.clear();
bf.put("testmessage".getBytes());
sc.write(bf);
// If the connection is dead, remove it from the selector
// and close it
if (!ok) {
key.cancel();
Socket s = null;
try {
s = sc.socket();
System.out.println( "Closing connection to "+s );
s.close();
} catch( IOException ie ) {
System.err.println( "Error closing socket "+s+": "+ie );
}
}
} catch( IOException ie ) {
// On exception, remove this channel from the selector
key.cancel();
try {
sc.close();
} catch( IOException ie2 ) { System.out.println( ie2 ); }
System.out.println( "Closed "+sc );
ie.printStackTrace();
}
}
}
// We remove the selected keys, because we've dealt with them.
keys.clear();
}
} catch( IOException ie ) {
System.err.println( ie );
}
}
On the server, please note the lines:
ByteBuffer bf = ByteBuffer.allocate(48);
bf.clear();
bf.put("testmessage".getBytes());
sc.write(bf);
This is where I try to answer back.
Client receives the messages in a method:
// Main method for incoming
public void run() throws IOException {
while(true) {
InputStream is = con.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String answer = br.readLine();
printMessage(answer);
}
}
Regards,
Pedro

Several problems here.
You're reading lines but you're not writing lines. Add a line terminator when sending.
You need to close the channel immediately you get -1 from read(). You almost certainly can't send on it after that.
You don't need to cancel the key or close the socket of the channel. Closing the channel does all that.
Your client read loop needs to break when you get null from readLine().

Related

Unity Mirror - NetworkServer Send Message To Target Client

I'm not sure what I'm doing wrong here but I can't seem to get my message from the server to the client. Here is what I have so far:
protected virtual void RegisterHandlers(bool enable)
{
if (enable)
{
NetworkServer.RegisterHandler<ClientRequestLoadScene>(OnClientRequestedToLoadScene);
NetworkClient.RegisterHandler<ServerRequestLoadScene>(OnServerRequestLoadScene);
}
else
{
NetworkServer.UnregisterHandler<ClientRequestLoadScene>();
NetworkClient.UnregisterHandler<ServerRequestLoadScene>();
}
}
The above is called when the instance starts to register a new handler. Then I have the client call:
ClientRequestLoadScene msg = new ClientRequestLoadScene();
msg.scene = scene;
NetworkClient.Send(msg);
This is received by the server fine. Then the server runs the following:
private void OnClientRequestedToLoadScene(NetworkConnection conn, ClientRequestLoadScene msg)
{
...
...
ServerRequestLoadScene server_msg = new ServerRequestLoadScene();
server_msg.scene = msg.scene;
NetworkServer.SendToClientOfPlayer(conn.identity, msg);
...
...
}
The above message is never received by the client. I have also tried: NetworkServer.SendToAll(msg); and that is never received by the client either. What am I doing wrong?
The issue with the above is with these lines:
server_msg.scene = msg.scene;
NetworkServer.SendToClientOfPlayer(conn.identity, msg);
It needed to be:
server_msg.scene = msg.scene;
conn.Send(server_msg);

Xamarin Forms How to change Port or IPAddress of socket connection

I have a UWP (soon to be MacOS also) application that listens for incoming messages. The user can configure which IP Address and Port to listen on. Once the socket connection is listening, the user can also go back into the settings and change the IP Address or Port. I am trying to figure out how to shut down the existing listener and restart it using the new Port / IP Address when the user changes the values. Here is my code that starts the listener. Any help would be appreciated.
private static Socket iobj_listener;
public async static Task StartListening()
{
try
{
Debug.WriteLine("Point 1");
IPEndPoint localEndPoint = new IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);
// Create a TCP/IP socket.
iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
iobj_listener.Bind(localEndPoint);
iobj_listener.Listen(100);
ViewModelObjects.AppSettings.ListeningOnSocket = true;
while (true)
{
Debug.WriteLine("Point 2");
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
iobj_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
iobj_listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
Debug.WriteLine("Point 3");
ViewModelObjects.AppSettings.ListeningOnSocket = false;
}
}
SO I could not find any quick answers so had to kind of figure this out on my own. If you see anything wrong with this, please let me know.
First of all I declared an e_Num as follows
public enum ge_SocketStatus
{
e_NotListening = 0,
e_Listening = 1,
e_Restart = 2
}
Then I added a StopListening function to my class that handles all my Socket communications and set the socket status to not listening as follows:
public static async Task StopListening()
{
try
{
if (iobj_listener.Connected)
{
//Wait till the connection ends or 30 seconds - this is so any last messages can be processed.
await Task.Delay(30000);
}
ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_NotListening;
iobj_listener.Close(1);
}
catch (Exception ex)
{
App.AppException(ex);
}
}
I then use the value of this enum to know when to end the loop:
public async static Task StartListening()
{
try
{
Debug.WriteLine("Point 1");
IPEndPoint localEndPoint = new IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);
// Create a TCP/IP socket.
iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
iobj_listener.Bind(localEndPoint);
iobj_listener.Listen(100);
ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_Listening;
while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)
{
Debug.WriteLine("Point 2");
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
iobj_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
iobj_listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
Debug.WriteLine("Point 3");
}
}
This line above
while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)
used to be
while (true)
so the loop would never end.
One gotcha I found is in the AcceptCallback used in the BeginAccept function of my socket. In this code, I also had to detect if the socket was connected because this function is called one last time after the StartListening loop exits. At the point the socket is not connected so trying to do anything with is, such as EndAccept, causes the application to throw an exception. Below you can see where I added the line
if (listener.Connected)
in order to stop the code from crashing after I had closed the connection.
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
//If we have shut down the socket don't do this.
if (listener.Connected)
{
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
Once all StopListening function ends and everything from the sockets is disconnected, I can call start listening again and open the socket on a different IPAddress and or Port.
I hope this helps as I could not find a good solution to this.

TCP Listener which should accept 100 threads per second

I have written code for TcpListener in c# which is supposed to receive request from client socket and process the request (send the processed request to our another web service to get final response) then parse the response and send the response back to client socket which initiated the request.
Code snippet below.
Code works fine when receive few requests at a time but now in order to move this to cloud and accept multiple request. We are testing this functionality by running JMeter test on same.
We are getting throughput like 4 when we hit 100 threads per seconds (end to end test - client system to server socket to our web service and back) which should be at least 30 to match client requirement.
If we omit the end to end flow and just send back to hardcode response from server socket itself we are seeing throughput 700.
To find the root cause I have added delay while sending hardcore response (same which we need to communicate with our web service) and I can see same behavior i.e. throughput drastically downgrades = 4/3.8
It means when TcpListener is busy processing existing request it may not attend the next requests (may be I am wrong in assumption - please correct if so)
Please have a look at code and help me increasing the performance .
public void StartTCPServer()
{
Logger.Write_Info_Log("In StartTCPServer - inPort : " + AESDK_CONFIG.PORT_NO, 1, log);
try
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, AESDK_CONFIG.PORT_NO);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception Ex)
{
Logger.Write_Fatal_Log("Exception in Start Listening : " + Ex.Message, 1, log);
}
}
public void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public void ReadCallback(IAsyncResult ar)
{
String strdata = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
strdata = state.sb.ToString();
if (!string.IsNullOrEmpty(strdata))
{
// All the data has been read from the client.
if (strdata.Contains("<<CheckConnection>>"))
{
log.Info(GlobalVar.gThreadNo(GlobalVar.gintCurrentThread) + "Data Received: " + strdata);
byte[] byData1 = System.Text.Encoding.UTF8.GetBytes("<<CheckConnectionAlive>>");
Send(handler, "<<CheckConnectionAlive>>");
}
else
{
Interlocked.Increment(ref m_clientCount);
//Process incoming requests here and send response back to client
string strResponse = GetRequest(strdata, m_clientCount);
Send(handler, strResponse);
}
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}

How do I correctly read and write with a Socket/NetworkStream using C# async/await in a single thread?

I'm attempting to write a client in C# for a proprietary TCP protocol connection (that sends/receives key+value pair messages). I'm wanting to use the async/await features of NetworkStream so my program can read and write to the socket with a single thread (a la JavaScript) however I'm having problems with the way NetworkStream.ReadAsync works.
Here's my program in outline:
public static async Task Main(String[] args)
{
using( TcpClient tcp = new TcpClient() )
{
await tcp.ConnectAsync( ... );
using( NetworkStream ns = tcp.GetStream() )
{
while( true )
{
await RunInnerAsync( ns );
}
}
}
}
private static readonly ConcurrentQueue<NameValueCollection> pendingMessagesToSend = new ConcurrentQueue<NameValueCollection>();
private static async Task RunInnerAsync( NetworkStream ns )
{
// 1. Send any pending messages.
// 2. Read any newly received messages.
// 1:
while( !pendingMessagesToSend.IsEmpty )
{
// ( foreach Message, send down the NetworkStream here )
}
// 2:
Byte[] buffer = new Byte[1024];
while( ns.DataAvailable )
{
Int32 bytesRead = await ns.ReadAsync( buffer, 0, buffer.Length );
if( bytesRead == 0 ) break;
// ( process contents of `buffer` here )
}
}
There's a problem here: if there is no data in the NetworkStream ns to be read (DataAvailable == false) then the while( true ) loop in Main constantly runs and the CPU never idles - this is bad.
So if I change the code to remove the DataAvailable check and simply always call ReadAsync then the call effectively "blocks" until data is available - so if no data arrives then this client will never send any messages to the remote host. So I thought about adding a timeout of 500ms or so:
// 2:
Byte[] buffer = new Byte[1024];
while( ns.DataAvailable )
{
CancellationTokenSource cts = new CancellationTokenSource( 500 );
Task<Int32> readTask = ns.ReadAsync( buffer, 0, buffer.Length, cts.Token );
await readTask;
if( readTask.IsCancelled ) break;
// ( process contents of `buffer` here )
}
However, this does not work! Apparently the NetworkStream.ReadAsync overload that accepts a CancellationToken does not abort or stop when a cancellation is actually requested, it always ignores it (how is this not a bug?).
The QA I linked to suggests a workaround of simply closing the Socket/NetworkStream - which is inappropriate for me because I need to keep the connection alive, but only take a break from waiting for data to arrive and send some data instead.
One of the other answers suggests co-awaiting a Task.Delay, like so:
// 2:
Byte[] buffer = new Byte[1024];
while( ns.DataAvailable )
{
Task maxReadTime = Task.Delay( 500 );
Task readTask = ns.ReadAsync( buffer, 0, buffer.Length );
await Task.WhenAny( maxReadTime, readTask );
if( maxReadTime.IsCompleted )
{
// what do I do here to cancel the still-pending ReadAsync operation?
}
}
...however while this does stop the program from waiting for an indefinite network read operation, it doesn't stop the read operation itself - so when my program finishes sending any pending messages it will call into ReadAsync a second time while it's still waiting for data to arrive - and that means dealing with overlapped-IO and is not what I want at all.
I know when working with Socket directly and its BeginReceive / EndReceive methods you simply only ever call BeginReceive from within EndReceive - but how does one safely call BeginReceive for the first time, especially in a loop - and how should those calls be modified when using the async/await API instead?
I got it working by getting the Task from NetworkStream.ReadAsync and storing it in a mutable local variable that is set to null if there is no pending ReadAsync operation, otherwise it's an valid Task instance.
Unfortunately as async methods cannot have ref parameters I needed to move my logic into Main from RunInnerAsync.
Here's my solution:
private static readonly ConcurrentQueue<NameValueCollection> pendingMessagesToSend = new ConcurrentQueue<NameValueCollection>();
private static TaskCompletionSource<Object> queueTcs;
public static async Task Main(String[] args)
{
using( TcpClient tcp = new TcpClient() )
{
await tcp.ConnectAsync( ... );
using( NetworkStream ns = tcp.GetStream() )
{
Task<Int32> nsReadTask = null; // <-- this!
Byte[] buffer = new Byte[1024];
while( true )
{
if( nsReadTask == null )
{
nsReadTask = ns.ReadAsync( buffer, 0, buffer.Length );
}
if( queueTcs == null ) queueTcs = new TaskCompletionSource<Object>();
Task completedTask = await Task.WhenAny( nsReadTask, queueTcs.Task );
if( completedTask == nsReadTask )
{
while( ns.DataAvailable )
{
Int32 bytesRead = await ns.ReadAsync( buffer, 0, buffer.Length );
if( bytesRead == 0 ) break;
// ( process contents of `buffer` here )
}
}
else if( completedTask == queueTcs )
{
while( !pendingMessagesToSend.IsEmpty )
{
// ( foreach Message, send down the NetworkStream here )
}
}
}
}
}
}
And whenever pendingMessagesToSend is modified, the queueTcs is instantiated if null and has SetResult(null) called to un-await the Task completedTask = await Task.WhenAny( nsReadTask, queueTcs.Task ); line.
Since building this solution I don't feel as though I'm using TaskCompletionSource appropriately, see this QA: Is it acceptable to use TaskCompletionSource as a WaitHandle substitute?

UDP Socket receive fails in wp7

I am newbie for WP7 and Socket programming. I have gone through msdn sample code http://msdn.microsoft.com/en-us/library/hh202864(v=VS.92).aspx#Y4537 and tested for use. Send works fine but it couldn't receive, this is the code I have used for receiving udp packet data.
In this my Breakpoint always fails # if (e.SocketError == SocketError.Success)
public string Receive(int portNumber)
{
string response = "Operation Timeout";
// We are receiving over an established socket connection
if (_socket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, portNumber);
// Setup the buffer to receive the data
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
// Inline event handler for the Completed event.
// Note: This even handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
try
{
if (e.SocketError == SocketError.Success)
{
// Retrieve the data from the buffer
response = Encoding.UTF8.GetString(e.Buffer, e.Offset,e.BytesTransferred);
response = response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
}
catch (Exception ex)
{
ex.ToString();
}
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Receive request over the socket
_socket.ReceiveFromAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
Have you tried using the specific UDP support in WP7/Silverlight? Either using UdpSingleSourceMulticastClient or UdpAnySourceMulticastClient depending on your scenario and requirements. Here's an intro article on UDP in Silverlight # Working with Multicast