Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# TCP套接字服务器-检测传入数据的方法_C#_Sockets_Tcp - Fatal编程技术网

C# TCP套接字服务器-检测传入数据的方法

C# TCP套接字服务器-检测传入数据的方法,c#,sockets,tcp,C#,Sockets,Tcp,我正在尝试编写一个服务器,它将侦听端口,接受传入的客户端连接,然后将该客户端连接放入堆栈中,等待将来的消息到达。理想情况下,当消息到达时,我希望触发一个事件,然后允许服务器执行操作 我已经写了几乎所有的内容…我正在使用AcceptTCPClient()来实际建立一个新的客户端连接,这很好。然后我创建一个线程,将套接字传递给一个类,该类保存客户机状态和一些其他数据。但是,我认为在该线程上阻塞并等待将来传入的连接的唯一方法是调用NetworkStream.Read()之类的函数,然后阻塞直到字节到达

我正在尝试编写一个服务器,它将侦听端口,接受传入的客户端连接,然后将该客户端连接放入堆栈中,等待将来的消息到达。理想情况下,当消息到达时,我希望触发一个事件,然后允许服务器执行操作

我已经写了几乎所有的内容…我正在使用
AcceptTCPClient()
来实际建立一个新的客户端连接,这很好。然后我创建一个线程,将套接字传递给一个类,该类保存客户机状态和一些其他数据。但是,我认为在该线程上阻塞并等待将来传入的连接的唯一方法是调用NetworkStream.Read()之类的函数,然后阻塞直到字节到达

所以这里是一个基本问题-我使用Protobuff net,它允许我反序列化网络流,而不是单个字节数组。因此,通过读取前两个字节,我必须重置读取,将networkstream传递给protobuff反序列化方法,然后继续

我真正想要的是一种方法,该方法在检测到某些字节之前进行阻塞,但在准备就绪之前,不需要我实际读取这些字节

有人知道我怎样才能做到这一点吗

更新

正如下面的评论所指出的,这似乎不是.Net所支持的,因此最简单的解决方案似乎是使用下面使用异步读/写的Tsukasa示例

我编写它是为了消耗线路上的所有字节,然后将这些字节传递给protobuff反序列化方法

这不是我想要的,但效果很好。谢谢大家的帮助

    private byte[] buffer = new byte[256];
    private Socket socket;
    private NetworkStream networkStream;
    private AsyncCallback callbackRead;
    private AsyncCallback callbackWrite;

    public Socket Socket
    {
        get { return socket; }            
    }

    public ClientProxy(Socket clientSocket)
    {
        socket = clientSocket;
        networkStream = new NetworkStream(clientSocket);
        callbackRead = new AsyncCallback(OnReadComplete);
        callbackWrite = new AsyncCallback(OnWriteComplete);
    }

    public void ReadAsync()
    {
        networkStream.BeginRead(buffer, 0, buffer.Length, callbackRead, null);
    }

    private void OnReadComplete(IAsyncResult ar)
    {
        int bytesRead = networkStream.EndRead(ar);

        if (bytesRead > 0)
        {                
            MemoryStream stream = new MemoryStream(buffer);
            Message data;
            data = Serializer.DeserializeWithLengthPrefix<Message>(stream, PrefixStyle.Fixed32);

            if (data.Type == Chat.Type.User && data.Action == Chat.Action.Add)
            {
                Communication.RegisterClient(data.From, socket.Handle.ToString());
            }                
            Communication.readMessage(data);

            ReadAsync();
        }
        else
        {
            networkStream.Close();
            socket.Close();
            networkStream = null;
            socket = null;
        }
    }
private byte[]buffer=新字节[256];
专用插座;
专用网络流;
私有异步回调回调回读;
私有异步回调回调回写;
公用插座
{
获取{返回套接字;}
}
公共客户端代理(套接字客户端套接字)
{
socket=clientSocket;
networkStream=新的networkStream(clientSocket);
callbackRead=新的异步回调(OnReadComplete);
callbackWrite=新的异步回调(OnWriteComplete);
}
public void ReadAsync()
{
networkStream.BeginRead(buffer,0,buffer.Length,callbackRead,null);
}
私有void OnReadComplete(IAsyncResult ar)
{
int bytesRead=networkStream.EndRead(ar);
如果(字节读取>0)
{                
MemoryStream stream=新的MemoryStream(缓冲区);
消息数据;
data=Serializer.DeserializeWithLengthPrefix(流,PrefixStyle.Fixed32);
if(data.Type==Chat.Type.User&&data.Action==Chat.Action.Add)
{
Communication.RegisterClient(data.From、socket.Handle.ToString());
}                
通信。读取消息(数据);
ReadAsync();
}
其他的
{
networkStream.Close();
socket.Close();
networkStream=null;
socket=null;
}
}
BeginRead(),它允许您在数据准备就绪时调用事件,这样您的进程可能处于阻塞状态,操作系统仅在资源准备就绪时才会唤醒它

class Client
{
    private byte[] buffer = new byte[256];
    private Socket socket;
    private NetworkStream networkStream;
    private AsyncCallback callbackRead;
    private AsyncCallback callbackWrite;

    public Client(Socket clientSocket)
    {
        socket = clientSocket;
        networkStream = new NetworkStream(clientSocket);
        callbackRead = new AsyncCallback(OnReadComplete);
        callbackWrite = new AsyncCallback(OnWriteComplete);
    }

    public void StartRead()
    {
        networkStream.BeginRead(buffer, 0, buffer.Length, callbackRead, null);
    }

    private void OnReadComplete(IAsyncResult ar)
    {
        int bytesRead = networkStream.EndRead(ar);

        if (bytesRead > 0)
        {
            string s = System.Text.Encoding.ASCII.GetString(buffer, 0, bytesRead);
            //do something with complete data here
            networkStream.BeginWrite(buffer, 0, bytesRead, callbackWrite, null);
        }
        else
        {
            networkStream.Close();
            socket.Close();
            networkStream = null;
            socket = null;
        }
    }

    private void OnWriteComplete(IAsyncResult ar)
    {
        networkStream.EndWrite(ar);
        networkStream.BeginRead(buffer, 0, buffer.Length, callbackRead, null);
    }
}
用法


您可以轮询
DataAvailable
属性,但它不可靠且效率低下

更好的方法是在protobuf流前面加上长度前缀。它还允许在不读取protobuf消息的情况下进行读取。通过使用前缀,您可以调用异步读取,该读取将在有可用内容时立即返回(如果您使用的是长度标头,则只需将读取配置为仅读取4个字节)


如果您不想自己处理网络操作,可以使用我的apache许可库。下面是一个使用protobuf net的示例:

尝试使用TcpListener类。@user1929959。。。这将有助于如何解决问题?你应该使用一个缓冲内存流,并通过它从网络流中读取。@user1929959,这并不能解决他的问题。你能更具体一点吗?在流上使用protobuf网络块有什么问题吗?如果您关心线程数,我相信protobuf net支持异步IO。这并不能回答这个问题。他想知道如何让“HandleClientComms”线程阻塞,直到接收到数据,而不实际执行readAdded HandleClientComms有点隐藏:“然而,我唯一能想到的阻塞和等待该线程上未来传入连接的方法是调用NetworkStream.Read()之类的东西这个问题是问题的下一段。我想我被他问的问题弄糊涂了。而(myNetworkStream.DataAvailable),然后等待触发某个事件,然后处理数据?@Tsukasa目前我认为这个问题无法回答。我在等待澄清。@usr:afaik确切的问题没有解决方案吗?那么给出替代方案有什么不对呢?我们不知道他的问题是什么。这个问题目前无法回答。对于无法回答的问题,任何答案都是错误的。你知道他的问题是什么吗?他想阻止,但不是在protobuf网络内。不知道为什么。他是这样定义的:
我真正想要的是一种方法,在检测到某些字节之前一直阻塞,但在准备好之前不需要我实际读取字节。a)你没有提供一个现实的解决方案,b)这可能是一个误导性的要求。如果你不理解他想要实现什么,你就不能提供替代方案。这就是为什么我对你的第一个评论说:“好吧,确切的问题没有解决方案?那么提供替代方案有什么错?”。
bool running = true;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
TcpListener tcpListener = new TcpListener(localAddr, 3000);
tcpListener.Start();

while (running)
{
    while (!tcpListener.Pending())
    {
        Thread.Sleep(10);
    }

    Socket socket = tcpListener.AcceptSocket();
    Client client = new Client(socket);
    client.StartRead();
}