我正在尝试在 C# 中进行高级聊天。我对编程并不陌生,但它接近我的第一次 TCP 聊天。
问题是我的Socket
(服务器)看起来没有收到任何数据。在我的void ReceiveDataListener
which is aBackgroundWorker
中,我添加了一些Console.WriteLine();
来检查它锁定的位置,它只显示第一个Console.WriteLine("Receive Data Listener 0")
。我知道Socket.Receive()
在收到一些数据之前锁定是正常的,但即使我发送数据它似乎也保持锁定状态。
我还想添加我的事件onClientConnect
并且onClientDisconnect
可以正常调用,所以我知道客户端连接正常。
这是我的服务器类的代码:
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
}
}
这是我用来通过发送数据来测试服务器的代码:
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();