I have made a connection between server and client, the client send data to the server and receive a response, but i wanna send data from the server to client and receive the response from client to server, is it possible ? Here is my code :
[Client] :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace Multi_Client
{
class Program
{
private static Socket _clientSocket = new Socket
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
static void Main(string[] args)
{
Console.Title = "Client";
ConnectToServer();
RequestLoop();
Exit();
}
private static void ConnectToServer()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
Console.WriteLine("Connection attempt " + attempts);
_clientSocket.Connect(IPAddress.Loopback, 100);
}
catch (SocketException)
{
Console.Clear();
}
}
Console.Clear();
Console.WriteLine("Connected");
_clientSocket.Send(Encoding.ASCII.GetBytes("C1"));
}
private static void RequestLoop()
{
Console.WriteLine(#"<Type ""exit"" to properly disconnect client>");
SendRequest();
ReceiveResponse();
}
/// <summary>
/// Close socket and exit app
/// </summary>
private static void Exit()
{
SendString("exit"); // Tell the server we re exiting
_clientSocket.Shutdown(SocketShutdown.Both);
_clientSocket.Close();
Environment.Exit(0);
}
private static void SendRequest()
{
Console.Write("Send a request: ");
string request = Console.ReadLine();
SendString(request);
if (request.ToLower() == "exit")
{
Exit();
return;
}
}
private static void SendString(string text)
{
byte[] buffer = Encoding.ASCII.GetBytes(text);
_clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
}
private static void ReceiveResponse()
{
byte[] buffer = new byte[2048];
int received = _clientSocket.Receive(buffer, SocketFlags.None);
if (received == 0) return;
byte[] data = new byte[received];
Array.Copy(buffer, data, received);
string text = Encoding.ASCII.GetString(data);
Console.WriteLine(text);
}
}
}
[Server] :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.IO;
using NetworkCommsDotNet;
using System.Net.Sockets;
namespace Server
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private static Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static List<Socket> _clientSockets = new List<Socket>();
private static readonly int _BUFFER_SIZE = 2048;
private static byte[] _buffer = new byte[_BUFFER_SIZE];
string text;
Socket current;
Socket test;
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.richTextBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.richTextBox1.Text += text + "\n";
}
}
private void SetupServer()
{
SetText("Setting up server...");
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100));
_serverSocket.Listen(5);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
SetText("Server Setup");
}
/// <summary>
/// Close all connected client (we do not need to shutdown the server socket as its connections
/// are already closed with the clients)
/// </summary>
private static void CloseAllSockets()
{
foreach (Socket socket in _clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
_serverSocket.Close();
}
private void AcceptCallback(IAsyncResult AR)
{
Socket socket = null;
try
{
socket = _serverSocket.EndAccept(AR);
}
catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
{
return;
}
_clientSockets.Add(socket);
socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
SetText("Client connected, waiting for request...");
test = (Socket)AR.AsyncState;
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private void ReceiveCallback(IAsyncResult AR)
{
current = (Socket)AR.AsyncState;
int received = 0;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
SetText("Client forcefully disconnected");
current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
_clientSockets.Remove(current);
return;
}
byte[] recBuf = new byte[received];
Array.Copy(_buffer, recBuf, received);
text = Encoding.ASCII.GetString(recBuf);
SetText("Received Text: " + text);
if (text.ToLower() == "get tim") // Client requested time
{
SetText("Text is a get time request");
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
current.Send(data);
SetText("Time sent to client");
}
else if (text.ToString() == "C1") // Client wants to exit gracefully
{
SetText("Received :: C1");
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
current.Send(data);
}
else
{
SetText("Server is sending invalid packet");
SetText("Warning Sent");
}
current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, new AsyncCallback(ReceiveCallback), current);
}
private void Form1_Load(object sender, EventArgs e)
{
SetupServer();
}
private void Send_Received(string mess)
{
byte[] data = Encoding.ASCII.GetBytes(mess);
test.Send(data);
}
private void button2_Click(object sender, EventArgs e)
{
CloseAllSockets();
}
private void button1_Click(object sender, EventArgs e)
{
Send_Received(textBox1.Text);
}
}
}
Short answer: Yes, it is possible.
Long aswer: Yes. Your current code is implemented this way:
Server initializes and prepares to receive connections.
Client tries to connect.
Server accepts connection, adds to clientSockets collection.
Client sends "C1".
Server receives content, interprets, and send answer back.
Client receives answer.
And then you enter a loop, since no other content is sent. You implemented a synchronous protocol - client talks, server talks back, client dumps it to console.
Let me suggest a quick implementation so you can test a server->client->server exchange:
Implement an asynchronous timer on your server.
After 10 seconds, if no incoming message arrives from an specific client, send a "PING?" message to it.
Parse the incoming content on the client. If the message is equal to "PING?", answer with a "PONG!".
This is a very simple QoS protocol - you'll be testing the connection's health.
Let us know if you manage to implement it. =)
Actually, i know where is the problem, when the server send something to the client and the client hasn't already sent something, the client doesn't show the thing until he sent another stuff :O
Example (i know it's complicated) :
Server sent C1 and show in the console C1 sent to client : Client do nothing (he should show in the console C1O)
Client sent Pa (random) and show in the console CAO : Server receive Pa
Client sent Ka (random) and show in the console (Invalid request because the server has received Pa so it sends invalid request text)
I hope that it's clean even if i knew that it's not :S
I resolved it by editing the RequestLoop function :
private static void RequestLoop()
{
ReceiveResponse();
}
It`s all :)
Related
I've been using AbleOpus example of sockets to build some test scenarios for a socket service I want to set up in my internal project. The code can be found here: Code example
I thought I understood when a static item/method was considered thread-safe but this one is causing me to second guess what I know. This could all revolve around how I perceived the use of a static object and read-only. How buffer is being used is what I'm not sure about private static readonly byte[] buffer = new byte[BUFFER_SIZE];. So at a 1000 foot view my understand of readonly is that you can set something at runtime. In this case, when the console application starts, it news set to a new byte[] and this is a forever running console application. After this it's used when it Accepts a call back and on a RecieveCallBack. Since the buffer is set at runtime, and then resused, does it not cause buffer to be overridded? Or is it because buffer is used inside of the method it sets up its own memory pointer?
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace MultiServer
{
class Program
{
private static readonly Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static readonly List<Socket> clientSockets = new List<Socket>();
private const int BUFFER_SIZE = 2048;
private const int PORT = 100;
private static readonly byte[] buffer = new byte[BUFFER_SIZE];
static void Main()
{
Console.Title = "Server";
SetupServer();
Console.ReadLine(); // When we press enter close everything
CloseAllSockets();
}
private static void SetupServer()
{
Console.WriteLine("Setting up server...");
serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT));
serverSocket.Listen(0);
serverSocket.BeginAccept(AcceptCallback, null);
Console.WriteLine("Server setup complete");
}
/// <summary>
/// Close all connected client (we do not need to shutdown the server socket as its connections
/// are already closed with the clients).
/// </summary>
private static void CloseAllSockets()
{
foreach (Socket socket in clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
serverSocket.Close();
}
private static void AcceptCallback(IAsyncResult AR)
{
Socket socket;
try
{
socket = serverSocket.EndAccept(AR);
}
catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
{
return;
}
clientSockets.Add(socket);
socket.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
Console.WriteLine("Client connected, waiting for request...");
serverSocket.BeginAccept(AcceptCallback, null);
}
private static void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
Console.WriteLine("Client forcefully disconnected");
// Don't shutdown because the socket may be disposed and its disconnected anyway.
current.Close();
clientSockets.Remove(current);
return;
}
byte[] recBuf = new byte[received];
Array.Copy(buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
Console.WriteLine("Received Text: " + text);
if (text.ToLower() == "get time") // Client requested time
{
Console.WriteLine("Text is a get time request");
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
current.Send(data);
Console.WriteLine("Time sent to client");
}
else if (text.ToLower() == "exit") // Client wants to exit gracefully
{
// Always Shutdown before closing
current.Shutdown(SocketShutdown.Both);
current.Close();
clientSockets.Remove(current);
Console.WriteLine("Client disconnected");
return;
}
else
{
Console.WriteLine("Text is an invalid request");
byte[] data = Encoding.ASCII.GetBytes("Invalid request");
current.Send(data);
Console.WriteLine("Warning Sent");
}
current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
}
}
}
I'm having a hard time naming this question and solving my problem.
I'm challenging myself in creating a chat server with multiple chat clients.
I've created a server that instantiates a new ClientManager object upon receiving a new connection via TCP. I'm missing various bits of management currently so ignore that as I'm focusing on figuring this bit out first:
Once the connection is established the ClientManager creates a new background worker for receiving streams. What I'm having trouble is once the stream is read, how can I forward that information back to my main server class to distribute amounts to the other clients (chat clients).
Once again, I'm missing a few management options such as threading, semaphores, etc but that will come as I build it out.
Here is how my server established a connection:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;
namespace ChatServer
{
class Program
{
private IPAddress localAddr;
private int serverPort;
private BackgroundWorker bwListener;
private List<ClientManager> clients;
private TcpListener server;
static void Main(string[] args)
{
Program progInstance = new Program();
progInstance.clients = new List<ClientManager>();
progInstance.server = null;
try
{
// Set the TcpListener on port 13000.
progInstance.serverPort = 13000;
progInstance.localAddr = IPAddress.Parse("127.0.0.1");
// Start to listen
progInstance.bwListener = new BackgroundWorker();
progInstance.bwListener.WorkerSupportsCancellation = true;
progInstance.bwListener.DoWork += new DoWorkEventHandler(progInstance.ServerListen);
progInstance.bwListener.RunWorkerAsync();
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
//progInstance.server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
private void ServerListen(object sender, DoWorkEventArgs e) {
this.server = new TcpListener(this.localAddr, this.serverPort);
this.server.Start();
// Enter the listening loop.
while (true)
{
Console.Write("Waiting for a connection... \n");
Socket client = server.AcceptSocket();
this.AcceptClientConnection(client);
}
}
private void AcceptClientConnection(Socket client) {
ClientManager newClient = new ClientManager(client);
this.clients.Add(newClient);
}
private void DisplayClientConnections() {
}
}
}
And this is the ClientManager
using System;
using System.Net.Sockets;
using System.ComponentModel;
namespace ChatServer
{
class ClientManager
{
NetworkStream stream;
private Socket socket;
private BackgroundWorker bwReceiver;
//data = null;
public ClientManager(Socket socket)
{
this.socket = socket;
this.stream = new NetworkStream(this.socket);
this.bwReceiver = new BackgroundWorker();
this.bwReceiver.DoWork += new DoWorkEventHandler(StartReceive);
this.bwReceiver.RunWorkerAsync();
}
private void StartReceive(object sender, DoWorkEventArgs e) {
String data = null;
Byte[] bytes = new Byte[256];
int i;
while (this.socket.Connected) {
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
}
}
}
}
}
I was thinking that the server should somehow retrieve this information and then write it to the stream, or would I just do that would I just write back to the stream from the ClientManager and then have my actual clients listen and receive? I'm just super lost how to handle this portion of the chat server.
I'm trying to create a program that listens to my server via a TCP Socket so it can be notified. For example, if I update the price of an item, all clients connected to the TCP Server gets sent a JSON string telling them so. The idea is that my C# program maintains this TCP Socket throughout run time, reading from the socket whenever there is new data.
My problem is that TcpClient is refusing to read past the first round of bytes being sent. It reads that and then just stops working altogether. Code is as follows:
TcpClient _client;
static int readBytesLength = 1024;
Byte[] readBytes = new byte[readBytesLength];
private void initClientConnection() {
_client = new TcpClient();
_client.BeginConnect(SERVER_IP, SERVER_PORT, new AsyncCallback(connectCallback), _client);
}
private void connectCallback(IAsyncResult result) {
if (_client.Connected) {
Console.WriteLine("Connected!");
this.beginReading();
}
else {
Console.WriteLine("Failed to connect, trying again!");
this.initClientConnection();
}
}
private void beginReading() {
readBytes = new byte[readBytesLength];
_client.GetStream().BeginRead(readBytes, 0, readBytesLength, receiveCallback, _client.GetStream());
}
private void receiveCallback(IAsyncResult result) {
Console.WriteLine("Read Callback!");
if (_client.GetStream().CanRead) {
string response = Encoding.UTF8.GetString(readBytes);
Console.WriteLine("Stream got \n{0}", response);
}
this.beginReading();
}
Again, I only receive 1 batch data and it just stops receiving.
Stream got
-----Received-----
{"status":"SUCCESS","message": "Log in confirmed (2)"}
There are still a few weird things going on in your code. There's no reason to use Stream.CanRead where you are using it, and you aren't using the correct overload of Encoding.GetString. I've cleaned up your example a bit and fixed some oddities/unnecessary bits.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class TcpConnection
{
private const int BUF_SIZE = 1024;
private readonly byte[] buffer = new byte[BUF_SIZE];
private readonly TcpClient client = new TcpClient();
public void Start(IPAddress ip, int port)
{
client.BeginConnect(ip, port, ConnectCallback, null);
}
private void ConnectCallback(IAsyncResult result)
{
client.EndConnect(result);
Console.WriteLine("Connected!");
}
private void StartRead()
{
if(!client.Connected)
{
Console.WriteLine("Disconnected, can't read.");
return;
}
NetworkStream stream = client.GetStream();
stream.BeginRead(buffer, 0, BUF_SIZE, ReadCallback, stream);
}
private void ReadCallback(IAsyncResult result)
{
NetworkStream stream = (NetworkStream)result.AsyncState;
int bytesRead = stream.EndRead(result);
Console.WriteLine("Read Callback!");
if (bytesRead > 0)
{
string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Stream got \n{0}", response);
}
StartRead();
}
}
I've been playing with some c# socket code that I found at MSDN (original server code and client code) and I've run into a problem that I don't understand. First, here is my socket server code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace AsyncSocketServerTest
{
class Program
{
public class StateObject
{
public Socket socket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public List<byte> bytes = new List<byte>();
}
public static ManualResetEvent allDone = new ManualResetEvent(false);
private const string ipAdd = "127.0.0.1";
public static void StartListening()
{
byte[] bytes = new byte[1024];
IPAddress ipAddress = IPAddress.Parse(ipAdd);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 25981);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.socket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
Console.WriteLine("Inside ReadCallback()...");
// retrieve the state object and the handler socket from the asynchronous state object
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
// read data from the client socket
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0)
{
// there might be more data, so store the data received so far
for (int bufferIndex = 0; bufferIndex < bytesRead; bufferIndex++)
{
state.bytes.Add(state.buffer[bufferIndex]);
}
socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
else
{
if (state.bytes.Count > 0)
{
// All the data has been read from the client; display it on the console.
byte[] bytesReceived = state.bytes.ToArray();
Console.WriteLine("Received {0} bytes from client...", bytesReceived.Length.ToString());
}
// generate a 50 byte response to send back to the client
Random r = new Random();
byte[] responseToSend = new byte[50];
r.NextBytes(responseToSend);
// *** THIS APPEARS TO BE CAUSING A PROBLEM ***
// send the response back to client
SendBytes(socket, responseToSend);
// ********************************************
// edit - commented out; the socket shouldn't be closed before the response is sent back to the client asynchronously
//socket.Close();
}
}
private static void SendBytes(Socket client, byte[] bytesToSend)
{
client.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
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());
}
}
static void Main(string[] args)
{
StartListening();
Console.ReadKey();
}
}
}
And now for the client code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace AsyncSocketClientTest
{
class Program
{
public class StateObject
{
public Socket socket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public List<byte> bytes = new List<byte>();
}
private const string ipAdd = "127.0.0.1";
// ManualResetEvent instances signal completion
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
private static void StartClient()
{
try
{
IPAddress ipAddress = IPAddress.Parse(ipAdd);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, 25981);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEndPoint, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// generate 100 random bytes to send to the server
Random r = new Random();
byte[] buffer = new byte[100];
r.NextBytes(buffer);
// send data to the server
SendBytes(client, buffer);
sendDone.WaitOne();
// *** THIS APPEARS TO BE CAUSING A PROBLEM ***
// receive the response from the remote host
ReceiveBytes(client);
receiveDone.WaitOne();
// ********************************************
// release the socket
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// retrieve the socket from the state object
Socket client = (Socket)ar.AsyncState;
// complete the connection
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
// signal that the connection has been made
connectDone.Set();
}
catch (SocketException sockEx)
{
// if the server isn't running, we're going to get a socket exception here...
Console.WriteLine(sockEx.Message);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveBytes(Socket client)
{
Console.WriteLine("Inside ReceiveBytes()...");
try
{
// create the state object
StateObject state = new StateObject();
state.socket = client;
// begin receiving data from the remote device
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
Console.WriteLine("Inside ReceiveCallback()...");
try
{
// Retrieve the state object and the client socket from the asynchronous state object
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.socket;
// Read data from the remote host
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// there might be more data, so store the data received so far
for (int bufferIndex = 0; bufferIndex < bytesRead; bufferIndex++)
{
state.bytes.Add(state.buffer[bufferIndex]);
}
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.bytes.Count > 0)
{
// All the data has been read from the client; display it on the console.
byte[] bytesReceived = state.bytes.ToArray();
Console.WriteLine("Read {0} bytes from socket...", bytesReceived.Length.ToString());
}
// Signal that all bytes have been received
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void SendBytes(Socket client, byte[] bytesToSend)
{
// Begin sending the data to the remote device
client.BeginSend(bytesToSend, 0, bytesToSend.Length, 0, new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// retrieve the socket from the state object
Socket client = (Socket)ar.AsyncState;
// complete sending the data to the remote device
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// signal that all bytes have been sent
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
static void Main(string[] args)
{
StartClient();
}
}
}
If I comment out the code in the client that receives the response back from the server as well as the code in the server that attempts to send the response to the client, then things appear to be working as you would expect (i.e., the client connects to the server, sends data and the server receives the data properly). When I uncomment these sections of the code, however, I'm seeing some behavior that I don't understand. In this case, I see the client connect to the server and send data to it. On the server side, the code appears to hang inside ReadCallback(). To better illustrate this, when the code sections I mentioned previously are commented out, I see this:
Client output:
Socket connected to 127.0.0.1:25981
Sent 100 bytes to server.
Server output:
Waiting for a connection...
Waiting for a connection...
Inside ReadCallback()...
Inside ReadCallback()...
Received 100 bytes from client...
As you can see from this output, when the server receives the 100 bytes of client data, I see two calls to ReadCallback(). So now I uncomment the aforementioned code and run it again. This time, I see:
Client output:
Socket connected to 127.0.0.1:25981
Sent 100 bytes to server.
Inside ReceiveBytes()...
Server output:
Waiting for a connection...
Waiting for a connection...
Inside ReadCallback()...
This time, my client sends 100 bytes of data to the server, sets the sendDone ManualResetEvent and then goes into ReceiveBytes(). On the server side, I see a single call to ReadCallback() and nothing else. That leads me to believe that the server didn't properly finish reading the data from the client although I'm not sure why. What am I missing?
This doesn't really answer your exact question but may I suggest an alternate way to go about this? For me threads are a bit easier to understand and the code looks a bit cleaner:
Server
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication2 {
class Program {
static void Main(string[] args) {
ServerWorkThread objThread = new ServerWorkThread();
while(true) {
objThread.HandleConnection(objThread.mySocket.Accept());
}
}
}
public class ServerWorkThread {
public Socket mySocket;
public ServerWorkThread() {
IPEndPoint objEnpoint = new IPEndPoint(IPAddress.Parse("***.***.***.***"), 8888);
mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
mySocket.Bind(objEnpoint);
mySocket.Listen(100);
}
public void HandleConnection(Socket iIncomingSocket) {
Thread worker = new Thread(this.RecieveAndSend);
worker.Start(iIncomingSocket);
worker.Join();
}
public void RecieveAndSend(object iIncoming) {
Socket objSocket = (Socket)iIncoming;
byte[] bytes = new byte[1024];
int bytesRecieved = objSocket.Receive(bytes);
string strReceived = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRecieved);
Console.WriteLine("Received from client: " + strReceived);
Console.WriteLine("Sending acknowledgement to client");
string strSend = ("Command of: " + strReceived + " was processed successfully");
objSocket.Send(System.Text.Encoding.ASCII.GetBytes(strSend));
objSocket.Close();
}
}
}
Client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Client {
class Program {
static void Main(string[] args) {
ClientWorkThread thread1 = new ClientWorkThread("I am thread 1");
thread1.SendCommand();
ClientWorkThread thread2 = new ClientWorkThread("I am thread 2");
thread2.SendCommand();
ClientWorkThread thread3 = new ClientWorkThread("I am thread 3");
thread3.SendCommand();
Console.Read();
}
}
public class ClientWorkThread {
private Socket pSocket;
private string command;
public ClientWorkThread(string iCommand) {
IPEndPoint objEnpoint = new IPEndPoint(IPAddress.Parse("***.***.***.***"), 8888);
pSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
pSocket.Connect(objEnpoint);
command = iCommand;
}
public void SendCommand() {
Thread worker = new Thread(this.Send);
worker.Start(pSocket);
}
public void Send(object iSending) {
Socket objSocket = (Socket)iSending;
objSocket.Send(System.Text.Encoding.ASCII.GetBytes(command + " now DO WORK "));
Console.WriteLine("Sending: " + command + " now DO WORK ");
byte[] bytes = new byte[1024];
int bytesRecieved = objSocket.Receive(bytes);
string strReceived = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRecieved);
Console.WriteLine("Received from server: " + strReceived);
objSocket.Close();
}
}
}
Server output:
Received from client: I am thread 1 now DO WORK
Sending acknowledgement to client
Received from client: I am thread 2 now DO WORK
Sending acknowledgement to client
Received from client: I am thread 3 now DO WORK
Sending acknowledgement to client
Client output:
Sending: I am thread 2 now DO WORK
Sending: I am thread 3 now DO WORK
Received from server: Command of: I am thread 2 now DO WORK was processed successfully
Received from server: Command of: I am thread 3 now DO WORK was processed successfully
Sending: I am thread 1 now DO WORK
Received from server: Command of: I am thread 1 now DO WORK was processed successfully
You could also use thread.Join() to have them finish executing in order.
I am new to the concept of dictionaries. I have found a way to create a simple server that is able to handle multiple clients. Is there a way that I could use a dictionary/ConcurrentDictionary to hold information such as the time the connection was established and the port it is using for the various clients. I have created a separate sample dictionary but I don't know how to make it work with the server application or if it will even work. (The server is created using localhost and port 9090. The clients are also run locally).
Let me know if you need any clarification.
How/Where would i place the dictionary code block to allow it to hold established connection information or is there a different/better way of doing it?
Dictionary<int, DateTime> ServerDictionary = new Dictionary<int, DateTime>();
ServerDictionary.Add(9090, DateTime.Now.AddMinutes(5));
Console.WriteLine("Time List");
foreach (KeyValuePair<int, DateTime> time in ServerDictionary)
{
Console.WriteLine("Port = {0}, Time in 5 = {1}",
time.Key, time.Value);
}
Console.ReadKey();
Below is the Server code:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Multi_Server
{
class Program
{
private static Socket _serverSocket;
private static readonly List<Socket> _clientSockets = new List<Socket>();
private const int _BUFFER_SIZE = 2048;
private const int _PORT = 9090;
private static readonly byte[] _buffer = new byte[_BUFFER_SIZE];
static void Main()
{
Console.Title = "Server";
SetupServer();
Console.ReadLine(); // When we press enter close everything
CloseAllSockets();
}
private static void SetupServer()
{
Console.WriteLine("Setting up server...");
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, _PORT));
_serverSocket.Listen(5);
_serverSocket.BeginAccept(AcceptCallback, null);
Console.WriteLine("Server setup complete");
}
// Close all connected client
// (we do not need to shutdown the server socket
// as its connections are already closed with the clients)
private static void CloseAllSockets()
{
foreach (Socket socket in _clientSockets)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
_serverSocket.Close();
}
private static void AcceptCallback(IAsyncResult AR)
{
Socket socket;
try
{
socket = _serverSocket.EndAccept(AR);
}
catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
{
return;
}
_clientSockets.Add(socket);
socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
Console.WriteLine("Client connected, waiting for request...");
_serverSocket.BeginAccept(AcceptCallback, null);
}
private static void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
Console.WriteLine("Client forcefully disconnected");
current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
_clientSockets.Remove(current);
return;
}
byte[] recBuf = new byte[received];
Array.Copy(_buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
Console.WriteLine("Received Text: " + text);
if (text.ToLower() == "get time") // Client requested time
{
Console.WriteLine("Text is a 'get time' request");
byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString());
current.Send(data);
Console.WriteLine("Time sent to client");
}
else if (text.ToLower() == "exit") // Client wants to exit gracefully
{
// Always Shutdown before closing
current.Shutdown(SocketShutdown.Both);
current.Close();
_clientSockets.Remove(current);
Console.WriteLine("Client disconnected");
return;
}
else
{
//Console.WriteLine("Text is an invalid request");
byte[] data = Encoding.ASCII.GetBytes("Invalid function request");
current.Send(data);
//Console.WriteLine("Warning Sent");
}
current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
}
}
}
Since multiple threads can access your dictionary at the same time, you either need to manually serialize access to it (with a lock statement) or user a ConcurrentDictionary. The latter will give better performance, in general. You could declare the dictionary to be a member of your Program class and insert into it from the AcceptCallback function.
Your _clientSockets List is also shared between threads and so it too needs some synchronization. Perhaps you can get rid of it altogether once your dictionary is working.