Reputation: 396
I am trying to make an advanced chat in C#. I am not new to programming but it is close to my first TCP chat.
The problem is that my Socket
(server) looks to not receive any datas. In my void ReceiveDataListener
which is a BackgroundWorker
, I added some Console.WriteLine();
to check where it locks and it only display the first Console.WriteLine("Receive Data Listener 0")
. I know it is normal that Socket.Receive()
lock until some datas are received but it seems to stay locked even if I send datas.
I also want to add that my event onClientConnect
and onClientDisconnect
are invoked fine so I know the clients connects fine.
Here is the code of my Server class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;
using System.Threading;
namespace JAChat.Library
{
class SocketServer
{
private Socket socket;
private BackgroundWorker bwSocketConnectListener;
private BackgroundWorker bwCheckIfConnected;
private BackgroundWorker bwReceiveDataListener;
private List<ClientManager> clientsList;
#region Constructor
public SocketServer(int port)
{
clientsList = new List<ClientManager>();
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, port));
socket.Listen(100);
bwSocketConnectListener = new BackgroundWorker();
bwSocketConnectListener.DoWork += new DoWorkEventHandler(ListenSocketConnection);
bwSocketConnectListener.RunWorkerAsync();
bwCheckIfConnected = new BackgroundWorker();
bwCheckIfConnected.DoWork += CheckIfClientStillConnectedThread;
bwCheckIfConnected.RunWorkerAsync();
bwReceiveDataListener = new BackgroundWorker();
bwReceiveDataListener.DoWork += ReceiveDataListener;
bwReceiveDataListener.RunWorkerAsync();
}
#endregion
#region Getter
public List<ClientManager> connectedClients
{
get
{
return clientsList;
}
}
#endregion
#region Public Methods
/// <summary>
/// Parse and send the command object to targets
/// </summary>
public void sendCommand(Command cmd)
{
BackgroundWorker test = new BackgroundWorker();
test.DoWork += delegate {
foreach(ClientManager cManager in clientsList){
cManager.sendCommand(cmd);
}
};
test.RunWorkerAsync();
}
/// <summary>
/// Disconnect and close the socket
/// </summary>
public void Disconnect()
{
socket.Disconnect(false);
socket.Close();
socket = null; //Stop some background worker
}
#endregion
#region Private Methods
private void ListenSocketConnection(object sender, DoWorkEventArgs e)
{
while (socket != null)
{
//Get and WAIT for new connection
ClientManager newClientManager = new ClientManager(socket.Accept());
clientsList.Add(newClientManager);
onClientConnect.Invoke(newClientManager);
}
}
private void CheckIfClientStillConnectedThread(object sender, DoWorkEventArgs e){
while(socket != null){
for(int i=0;i<clientsList.Count;i++){
if(clientsList[i].socket.Poll(10,SelectMode.SelectRead) && clientsList[i].socket.Available==0){
clientsList[i].socket.Close();
onClientDisconnect.Invoke(clientsList[i]);
clientsList.Remove(clientsList[i]);
i--;
}
}
Thread.Sleep(5);
}
}
private void ReceiveDataListener(object sender, DoWorkEventArgs e){
while (socket != null){
Console.WriteLine("Receive Data Listener 0");
//Read the command's Type.
byte[] buffer = new byte[4];
int readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
Console.WriteLine("Receive Data Listener 1");
if (readBytes == 0)
break;
Console.WriteLine("Receive Data Listener 2");
CommandType cmdType = (CommandType)(BitConverter.ToInt32(buffer, 0));
Console.WriteLine("Receive Data Listener 3");
//Read the sender IP size.
buffer = new byte[4];
readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
if (readBytes == 0)
break;
int senderIPSize = BitConverter.ToInt32(buffer, 0);
//Read the sender IP.
buffer = new byte[senderIPSize];
readBytes = this.socket.Receive(buffer, 0, senderIPSize, SocketFlags.None);
if (readBytes == 0)
break;
IPAddress cmdSenderIP = IPAddress.Parse(System.Text.Encoding.ASCII.GetString(buffer));
//Read the sender name size.
buffer = new byte[4];
readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
if (readBytes == 0)
break;
int senderNameSize = BitConverter.ToInt32(buffer, 0);
//Read the sender name.
buffer = new byte[senderNameSize];
readBytes = this.socket.Receive(buffer, 0, senderNameSize, SocketFlags.None);
if (readBytes == 0)
break;
string cmdSenderName = System.Text.Encoding.Unicode.GetString(buffer);
//Read target IP size.
string cmdTarget = "";
buffer = new byte[4];
readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
if (readBytes == 0)
break;
int targetIPSize = BitConverter.ToInt32(buffer, 0);
//Read the command's target.
buffer = new byte[targetIPSize];
readBytes = this.socket.Receive(buffer, 0, targetIPSize, SocketFlags.None);
if (readBytes == 0)
break;
cmdTarget = System.Text.Encoding.ASCII.GetString(buffer);
//Read the command's MetaData size.
string cmdMetaData = "";
buffer = new byte[4];
readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
if (readBytes == 0)
break;
int metaDataSize = BitConverter.ToInt32(buffer, 0);
//Read the command's Meta data.
buffer = new byte[metaDataSize];
readBytes = this.socket.Receive(buffer, 0, metaDataSize, SocketFlags.None);
if (readBytes == 0)
break;
cmdMetaData = System.Text.Encoding.Unicode.GetString(buffer);
//Create the command object
Command cmd = new Command(cmdType, cmdSenderIP, cmdSenderName, IPAddress.Parse(cmdTarget), cmdMetaData);
this.onCommandReceived(cmd);
}
Console.WriteLine("Receive data listener closed");
}
#endregion
#region Events
public delegate void OnClientConnectEventHandler(ClientManager client);
/// <summary>
/// Events invoked when a client connect to the server
/// </summary>
public event OnClientConnectEventHandler onClientConnect = delegate { };
public delegate void OnClientDisconnectEventHandler(ClientManager client);
/// <summary>
/// Events invoked when a client disconnect from the server
/// </summary>
public event OnClientDisconnectEventHandler onClientDisconnect = delegate { };
public delegate void OnCommandReceivedEventHandler(Command cmd);
/// <summary>
/// Events invoked when a command has been sent to the server
/// </summary>
public event OnCommandReceivedEventHandler onCommandReceived = delegate { };
#endregion
}
}
and here is the code that I use to test the server by sending datas :
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect("localhost", 2000);
networkStream = new NetworkStream(clientSocket);
//CommandType
byte[] buffer = new byte[4];
buffer = BitConverter.GetBytes(1);
this.networkStream.Write(buffer, 0, 4);
this.networkStream.Flush();
//Sender IP + Size
byte[] senderIPBuffer = Encoding.ASCII.GetBytes("192.54.67.8");
buffer = new byte[4];
buffer = BitConverter.GetBytes(senderIPBuffer.Length);
this.networkStream.Write(buffer, 0, 4);
this.networkStream.Flush();
this.networkStream.Write(senderIPBuffer, 0, senderIPBuffer.Length);
this.networkStream.Flush();
//Sender Name + Size
byte[] senderNameBuffer = Encoding.ASCII.GetBytes("James");
buffer = new byte[4];
buffer = BitConverter.GetBytes(senderNameBuffer.Length);
this.networkStream.Write(buffer, 0, 4);
this.networkStream.Flush();
this.networkStream.Write(senderNameBuffer, 0, senderNameBuffer.Length);
this.networkStream.Flush();
//Command Target IP + Size
byte[] targetIPBuffer = Encoding.ASCII.GetBytes("192.43.54.6");
buffer = new byte[4];
buffer = BitConverter.GetBytes(targetIPBuffer.Length);
this.networkStream.Write(buffer, 0, 4);
this.networkStream.Flush();
this.networkStream.Write(targetIPBuffer, 0, targetIPBuffer.Length);
this.networkStream.Flush();
//Command MetaData + Size
byte[] metaBuffer = Encoding.Unicode.GetBytes("Metadata contents");
buffer = new byte[4];
buffer = BitConverter.GetBytes(metaBuffer.Length);
this.networkStream.Write(buffer, 0, 4);
this.networkStream.Flush();
this.networkStream.Write(metaBuffer, 0, metaBuffer.Length);
this.networkStream.Flush();
Upvotes: 0
Views: 545
Reputation: 2846
Note: the server throws an exception right on startup (for me at least) in ReceiveDataListener, before any client has even attempted to connect, since the socket reader worker immediately tries to read from a socket that is in the listen state.
Hope that helps - Harold
Upvotes: 1