0

我正在尝试在 C# 中进行高级聊天。我对编程并不陌生,但它接近我的第一次 TCP 聊天。

问题是我的Socket(服务器)看起来没有收到任何数据。在我的void ReceiveDataListenerwhich 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();
4

1 回答 1

1
  1. SocketServer 有一个名为“socket”的类级变量
  2. SocketServer 的构造函数创建一个用于监听指定端口的套接字并将其保存为套接字的值
  3. ListenSocketConnection 正在调用 Socket.Accept (good) 并保留连接列表
  4. 错误:ReceiveDataListener 正在尝试从正在侦听指定端口的套接字中读取,而不是从 ListenSocketConnection 中的 Accept 调用返回的各个套接字中读取

注意:服务器在启动时(至少对我而言)在 ReceiveDataListener 中引发异常,甚至在任何客户端尝试连接之前,因为套接字读取器工作程序立即尝试从处于侦听状态的套接字读取。

希望有帮助 - 哈罗德

于 2013-10-07T12:30:06.467 回答