简体   繁体   English

C#Socket.receive连续接收0个字节,并且不会在循环中阻塞

[英]C# Socket.receive continuously receives 0 bytes and does not block in the loop

I am trying to write a simplest multithreaded TCP server in C#, which receives the data from multiple clients. 我试图用C#编写一个最简单的多线程TCP服务器,它接收来自多个客户端的数据。

Every time a new client is connected, the socket connection is established and the socket is passed as an argument to the new class function, after that the while loop runs and receives the data till the client is connected. 每次连接新客户端时,都会建立套接字连接,并将套接字作为参数传递给新的类函数,之后while循环运行并接收数据直到客户端连接。

The problem here is that the "socket.receive" is not blocking and receives 0 bytes of data. 这里的问题是“socket.receive”没有阻塞并且接收0字节的数据。 So the loop runs continuously, without blocking at socket.receive ("clientSocket.Receive(bb)" in the code.). 因此循环连续运行,而不会阻塞socket.receive(代码中的“clientSocket.Receive(bb)”。)。

I am using Chrome browser as a client for testing. 我使用Chrome浏览器作为客户端进行测试。 Even if I use any other client, the behavior of the TCP server remains the same. 即使我使用任何其他客户端,TCP服务器的行为仍然是相同的。

The client sends the data only once but server continuously receives 0 bytes and while loop keeps on running. 客户端仅发送一次数据,但服务器连续接收0个字节,而循环继续运行。

I am pasting the Server output for reference. 我粘贴服务器输出以供参考。

Please help in blocking the Server at socket.receive to wait for next client transmission. 请帮助阻塞socket.receive上的服务器以等待下一次客户端传输。 The strange thing is that even if 0 bytes are received, the exception is also not called. 奇怪的是,即使接收到0个字节,也不会调用异常。

Please help. 请帮忙。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
Threading;
using System.Timers;
using System.Security;
using System.Security.Permissions;
namespace SERVER
{
    static class Constants
    {
        public const int port = 8080;
        public const int buffer_size = 512;


    }
    class Program
    {
        static public string LocalIPAddress()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                    break;
                }
            }
            return localIP;
            //return ip;
        }

        static void Main(string[] args)
        {
            //IPEndPoint ipObj = new IPEndPoint(IPAddress.Parse("Server IP goes here"), 20487); //20487 is port. you can change it according to your wish
            System.Net.IPAddress IP = IPAddress.Any;
            int port = Constants.port;
            TcpListener listnerObj = new TcpListener(IP, port);
            listnerObj.Start();
            string client_addr;
            string[] client_addr_split;
            string IP_string = LocalIPAddress();

            Console.WriteLine("Server Started on {0}:{1}", IP_string, port);
            while (true)
            {
                Console.WriteLine("================================");
                Console.WriteLine("**    Waiting For Client     **");
                Socket clientSocket = listnerObj.AcceptSocket(); // waiting for the client to connect

                client_addr = clientSocket.RemoteEndPoint.ToString();
                client_addr_split = client_addr.Split(':');
                client_addr = client_addr_split[0];

                Console.WriteLine("Client Connected {0}", client_addr);
                ParameterizedThreadStart thread = delegate { new communication().doCommunicate(clientSocket, client_addr); };
                Thread th = new Thread(thread);
                th.Start(); // start the thread here 
            }
        }

        class communication
        {
            public int byteReceived;
            public byte[] bb;
            public void doCommunicate(Socket clientSocket, string client_addr)
            {
                clientSocket.Blocking = true;
                bb = new byte[Constants.buffer_size];

                //Console.WriteLine("***** Entered DoCommunicate *****");
                while (clientSocket.Connected)
                {
                    //Console.WriteLine("Entered While");
                    try
                    {
                        //Console.WriteLine("Entered TRY");
                        Console.WriteLine("Waiting to recieve Data from IP : client_addr");
                        //int ReceivedDataLength = Client.Receive(ReceivedBytes, 0, ReceivedBytes.Length, SocketFlags.None);
                        byteReceived = clientSocket.Receive(bb, 0, bb.Length, SocketFlags.None);
                        //byteReceived = clientSocket.Receive(bb);
                    }
                    catch (SocketException e)
                    {
                        Console.WriteLine("Error: Socket Exception.\n{0}\n{1}.", e.Message, e.ErrorCode);
                        break;
                    }
                    catch (ArgumentNullException e)
                    {
                        Console.WriteLine("Error : Argument Null Exception.\n{0}", e.Message);
                        break;
                    }
                    catch (ObjectDisposedException e)
                    {
                        Console.WriteLine("Error : Socket Disposed Exception Caught.\n{0}", e.Message);
                        break;
                    }
                    catch (SecurityException e)
                    {
                        Console.WriteLine("Error: Security Exception.\n{0}", e.Message);
                        break;
                    }
                    //clientSocketglobal.Send(Encoding.Default.GetBytes("Hello Client"), SocketFlags.None);
                    Console.WriteLineWriteLine("Received Byte count : {0}, from IP : {1}", byteReceived, client_addr); // Do whatever you want to do with the data recieved. Parsing and storing etc.
                    Console.WriteLine(Encoding.UTF8.GetString(bb));
                }
                //Console.WriteLine("While Loop Exited");
                Console.WriteLine("Socked and Class Object  Disposed");
                clientSocket.Close();
                clientSocket.Dispose();
                GC.Collect();
            }
        }
    }
}

OUTPUT Of server : OUTPUT服务器:

Server Started on 10.0.0.2:8080
================================
**    Waiting For Client     **
Client Connected 10.0.0.2
================================
**    Waiting For Client     **
Client Connected 10.0.0.2
================================
**    Waiting For Client     **
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 386, from IP : 10.0.0.2
GET /HelloWorld HTTP/1.1
Host: 10.0.0.2:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.69 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6


Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Waiting to recieve Data from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2
Received Byte count : 0, from IP : 10.0.0.2

If you received 0 bytes, that usually means the sender has closed their send socket. 如果您收到0个字节,这通常意味着发件人已关闭其发送套接字。 In a Socket , the send and receive channels are separate; Socket发送接收通道是分开的; I expect what is happening is that your send (their receive) is still open and available, hence clientSocket.Connected returning true (you can still send them a reply), but: they closed their send (your receive) as soon as they sent their payload (this is common, to indicate the end of a batch). 我希望发生的事情是你的发送(他们的接收)仍然是开放和可用的,因此clientSocket.Connected返回true(你仍然可以发送回复),但是:他们发送后立即关闭发送(你的接收)他们的有效载荷(这是常见的,表示批次的结束)。 Basically, you just need to detect the 0-byte receive, and treat that as the end: no more data will ever be incoming once you have had a non-positive reply from receive. 基本上,您只需要检测0字节接收,并将其视为结束:一旦您收到来自接收的非肯定回复,就不会再有数据传入。 So just write any response you need to write (they can still be listening, even though they will never speak again), and shutdown the socket. 所以只需编写你需要编写的任何响应(它们仍然可以监听,即使它们永远不会再说话),并关闭套接字。

As a side note: in HTTP/1.1 with Connection: keep-alive , the can keep their socket open ready to send the next request - but it just looks like in this case, they simply didn't. 作为旁注:在HTTP / 1.1中使用Connection: keep-alive可以保持其套接字打开以准备发送下一个请求 - 但它看起来就像在这种情况下,它们根本就没有。 They closed their socket immediately after issuing the request. 他们在发出请求后立即关闭了套接字。 Which is fine. 哪个好。 Just serve the response and close the socket completely. 只需提供响应并完全关闭套接字。 No more requests will be incoming. 不再有任何请求传入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM