C# 读取插座直到第C行结束?

C# 读取插座直到第C行结束?,c#,sockets,C#,Sockets,我正在尝试编写一个服务,该服务侦听给定端口上的TCP套接字,直到接收到行的末尾,然后根据接收到的“行”执行命令 我遵循了c#的基本socket编程教程,并编写了以下代码来收听socket: public void StartListening() { _log.Debug("Creating Maing TCP Listen Socket"); _mainSocket = new Socket(AddressFamily.Inter

我正在尝试编写一个服务,该服务侦听给定端口上的TCP套接字,直到接收到行的末尾,然后根据接收到的“行”执行命令

我遵循了c#的基本socket编程教程,并编写了以下代码来收听socket:

public void StartListening()
        {
            _log.Debug("Creating Maing TCP Listen Socket");
            _mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, _port);
            _log.Debug("Binding to local IP Address");
            _mainSocket.Bind(ipLocal);

            _log.DebugFormat("Listening to port {0}",_port);
            _mainSocket.Listen(10);

            _log.Debug("Creating Asynchronous callback for client connections");
            _mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);

        }

        public void OnClientConnect(IAsyncResult asyn)
        {
            try
            {
                _log.Debug("OnClientConnect Creating worker socket");
                Socket workerSocket = _mainSocket.EndAccept(asyn);
                _log.Debug("Adding worker socket to list");
                _workerSockets.Add(workerSocket);
                _log.Debug("Waiting For Data");
                WaitForData(workerSocket);

                _log.DebugFormat("Clients Connected [{0}]", _workerSockets.Count);

                _mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
            }
            catch (ObjectDisposedException)
            {
                _log.Error("OnClientConnection: Socket has been closed\n");
            }
            catch (SocketException se)
            {
                _log.Error("Socket Exception", se);
            }
        }

        public class SocketPacket
        {
            private System.Net.Sockets.Socket _currentSocket;

            public System.Net.Sockets.Socket CurrentSocket
            {
                get { return _currentSocket; }
                set { _currentSocket = value; }
            }
            private byte[] _dataBuffer = new byte[1];

            public byte[] DataBuffer
            {
                get { return _dataBuffer; }
                set { _dataBuffer = value; }
            }


        }

        private void WaitForData(Socket workerSocket)
        {
            _log.Debug("Entering WaitForData");
            try
            {
                lock (this)
                {
                    if (_workerCallback == null)
                    {
                        _log.Debug("Initializing worker callback to OnDataRecieved");
                       _workerCallback = new AsyncCallback(OnDataRecieved);
                    }
                }
                SocketPacket socketPacket = new SocketPacket();
                socketPacket.CurrentSocket = workerSocket;
                workerSocket.BeginReceive(socketPacket.DataBuffer, 0, socketPacket.DataBuffer.Length, SocketFlags.None, _workerCallback, socketPacket);
            }
            catch (SocketException se)
            {
                _log.Error("Socket Exception", se);
            }
        }

        public void OnDataRecieved(IAsyncResult asyn)
        {
            SocketPacket socketData = (SocketPacket)asyn.AsyncState;
            try
            {

                int iRx = socketData.CurrentSocket.EndReceive(asyn);
                char[] chars = new char[iRx + 1];
                _log.DebugFormat("Created Char array to hold incomming data. [{0}]",iRx+1);

                System.Text.Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
                int charLength = decoder.GetChars(socketData.DataBuffer, 0, iRx, chars, 0);
                _log.DebugFormat("Read [{0}] characters",charLength);

                String data = new String(chars);
                _log.DebugFormat("Read in String \"{0}\"",data);

                WaitForData(socketData.CurrentSocket);
            }
            catch (ObjectDisposedException)
            {
                _log.Error("OnDataReceived: Socket has been closed. Removing Socket");
                _workerSockets.Remove(socketData.CurrentSocket);

            }
            catch (SocketException se)
            {
                _log.Error("SocketException:",se);
                _workerSockets.Remove(socketData.CurrentSocket);

            }
        }
我认为这将是我想要做的一个很好的基础,但是我已经将输入字符一个接一个地添加到文本框中的代码没有做任何处理。这对我想做的事并不起作用

我的主要问题是OnDataReceived方法与Wait for data方法的解耦。这意味着我在构建字符串时遇到了问题(我会使用字符串生成器,但我可以接受多个连接,所以这实际上不起作用)

理想情况下,我希望边听套接字边看,直到看到和行尾字符,然后用结果字符串作为参数调用方法


执行此操作的最佳方法是什么。

尝试使用异步套接字。下面的代码将侦听套接字,如果通过telnet接收到新行字符,它将回显到输入套接字。您似乎只需要将该输入重定向到文本框

    private string _hostName;
    private const int _LISTENINGPORT = 23;
    private Socket _incomingSocket;
    byte[] _recievedData;
    //todo: do we need 1024 byte? the asynch methods read the bytes as they come
    //so when 1 byte typed == 1 byte read. Unless its new line then it is two.
    private const int _DATASIZE = 1024;

    public ConnectionServer()
    {
        IPAddress localAddr = IPAddress.Parse("127.0.0.1");
        _hostName = Dns.GetHostName();
        _recievedData = new byte[_DATASIZE];
        _incomingSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(localAddr, _LISTENINGPORT);
        _incomingSocket.Bind(endPoint);
        _incomingSocket.Listen(10);
    }
    ~ConnectionServer()
    {
    }
    public void StartListening()
    {
        _incomingSocket.BeginAccept(new AsyncCallback(OnAccept), _incomingSocket);
    }
    private void OnAccept(IAsyncResult result)
    {
        UserConnection connectionInfo = new UserConnection();
        Socket acceptedSocket = (Socket)result.AsyncState;
        connectionInfo.userSocket = acceptedSocket.EndAccept(result);
        connectionInfo.messageBuffer = new byte[_DATASIZE];
        //Begin acynch communication with target socket
        connectionInfo.userSocket.BeginReceive(connectionInfo.messageBuffer, 0, _DATASIZE, SocketFlags.None,
            new AsyncCallback(OnReceiveMessage), connectionInfo);
        //reset the listnening socket to start accepting 
        _incomingSocket.BeginAccept(new AsyncCallback(OnAccept), result.AsyncState);
    }
   private void OnReceiveMessage(IAsyncResult result)
        {
            UserConnection connectionInfo = (UserConnection)result.AsyncState;
            int bytesRead = connectionInfo.userSocket.EndReceive(result);
            if (connectionInfo.messageBuffer[0] != 13 && connectionInfo.messageBuffer[1] != 10)
            //ascii for newline and line feed
            //todo dress this up
            {
                if (string.IsNullOrEmpty(connectionInfo.message))
                {
                    connectionInfo.message = ASCIIEncoding.ASCII.GetString(connectionInfo.messageBuffer);
                }
                else
                {
                    connectionInfo.message += ASCIIEncoding.ASCII.GetString(connectionInfo.messageBuffer);
                }
            }
            else
            {
                connectionInfo.userSocket.Send(ASCIIEncoding.ASCII.GetBytes(connectionInfo.message), SocketFlags.None);
                connectionInfo.userSocket.Send(connectionInfo.messageBuffer, SocketFlags.None);
                connectionInfo.message = string.Empty;
                connectionInfo.messageBuffer = new byte[_DATASIZE];
            }


{
    public class UserConnection
    {
        public Socket userSocket { get; set; }
        public Byte[] messageBuffer { get; set; }
        public string message { get; set; }
    }
}

您似乎有几个问题:

您有一个名为
WaitForData
的异步方法。这非常令人困惑,因为名称中带有
Wait
一词的方法通常会阻止当前正在执行的线程,直到发生某些事情(或者,可选地,超时过期)。这正好相反。您希望这是同步操作还是异步操作

也不需要实例化
解码器
对象,也不需要任何东西的
字符
数组;只需调用
System.Text.Encoding.UTF8.GetString(socketData.DataBuffer,0,iRx)

你似乎也没有用线条做任何事情…这就是为什么它没有用线条做任何事情

您使用
StringBuilder
的方法就是我要做的。我会将
StringBuilder
添加到
SocketData
类中,并将其命名为
Builder
。在捕获字符串数据时,请执行以下操作:

string[] data = System.Text.Encoding.UTF8.GetString(
                    socketData.DataBuffer, 0, iRx).Split(Environment.NewLine);

socketData.Builder.Append(data[0]);

for(int i = 1; i < data.Length; i++)
{
    // the socketData.Builder variable now contains a single line, so do 
    // something with it here, like raise an event
    OnLineReceived(builder.ToString());

    socketData.Builder = new StringBuilder(data[i]);
}
string[]data=System.Text.Encoding.UTF8.GetString(
socketData.DataBuffer,0,iRx).Split(Environment.NewLine);
socketData.Builder.Append(数据[0]);
for(int i=1;i
这里需要注意的一点是,
UTF8
是一种多字节编码,这意味着您可能会捕获一块截断中间字符的数据。通常,最好在通信的另一端进行这种预处理,然后以适当长度的前缀格式发送数据。

我建议删除在本期和未来的问题中,我们将对极其冗长的日志代码进行详细说明。