C sharp socket recieve виснет

241
11 марта 2017, 00:28

Здравствуйте! По какой причине программа может виснуть до получения ответа на string answer = ReceiveDataFromServer();? Т.е. пока не получит сокет в ответ. Если она не получает просто висит. Если получает - то поломанная кодировка.

namespace HotKeyTest
{
public partial class Form1 : Form
{
    // Receiving byte array  
    byte[] bytes = new byte[1024];
    Socket senderSock;
    public Form1()
    {
        InitializeComponent();
        Boolean success = Form1.RegisterHotKey(this.Handle, this.GetType().GetHashCode(), 0x0002, 0x4c);//Set hotkey as 'ctrl+l'
    }
    private void button1_Click(object sender, EventArgs e)
    {
        StreamReader sr = new StreamReader("settings");
        IPAddress ip = IPAddress.Parse(sr.ReadLine());
        Connect(ip);
        sr.Close();
        Thread.Sleep(2000);
        Sendswitch();
        Disconnect();
    }
    private void Connect(IPAddress ip)
    {
        try
        {
            // Create one SocketPermission for socket access restrictions 
            SocketPermission permission = new SocketPermission(
                NetworkAccess.Connect,    // Connection permission 
                TransportType.Tcp,        // Defines transport types 
                "",                       // Gets the IP addresses 
                SocketPermission.AllPorts // All ports 
                );
            // Ensures the code to have permission to access a Socket 
            permission.Demand();
            // Resolves a host name to an IPHostEntry instance            
            IPHostEntry ipHost = Dns.GetHostEntry("");
            // Gets first IP address associated with a localhost 
            IPAddress ipAddr = ip;
            // Creates a network endpoint 
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 55443);
            // Create one Socket object to setup Tcp connection 
            senderSock = new Socket(
                ipAddr.AddressFamily,// Specifies the addressing scheme 
                SocketType.Stream,   // The type of socket  
                ProtocolType.Tcp     // Specifies the protocols  
                );
            senderSock.NoDelay = false;   // Using the Nagle algorithm 
            // Establishes a connection to a remote host 
            senderSock.Connect(ipEndPoint);
        }
        catch (Exception exc) { MessageBox.Show(exc.ToString()); }
    }
    private void Sendswitch()
    {
        try
        {
            // Sending message 
            //<Client Quit> is the sign for end of data 
            byte[] msg = Encoding.Unicode.GetBytes("{\"id\":1,\"method\":\"get_prop\",\"params\":[\"power\", \"not_exist\", \"bright\"]}");
            // Sends data to a connected Socket. 
            int bytesSend = senderSock.Send(msg);
            Thread.Sleep(2000);
            string answer = ReceiveDataFromServer();
            MessageBox.Show(answer);
        }
        catch (Exception exc) { MessageBox.Show(exc.ToString()); }
    }
    private string ReceiveDataFromServer()
    {
        try
        {
            // Receives data from a bound Socket. 
            int bytesRec = senderSock.Receive(bytes);
            // Converts byte array to string 
            String theMessageToReceive = Encoding.Unicode.GetString(bytes, 0, bytesRec);
            // Continues to read the data till data isn't available 
            while (senderSock.Available > 0)
            {
                bytesRec = senderSock.Receive(bytes);
                theMessageToReceive += Encoding.Unicode.GetString(bytes, 0, bytesRec);
            }
            return theMessageToReceive;
        }
        catch (Exception exc) { return exc.ToString(); }
    }
    private void Disconnect()
    {
        try
        {
            // Disables sends and receives on a Socket. 
            senderSock.Shutdown(SocketShutdown.Both);
            //Closes the Socket connection and releases all resources 
            senderSock.Close();
        }
        catch (Exception exc) { MessageBox.Show(exc.ToString()); }
    }
}

}

Answer 1

Раделим вопрос на две части - блокировка и испорченные данные.

согласно документации - https://msdn.microsoft.com/ru-ru/library/8s4y8aff(v=vs.110).aspx - вызов Receive блокирующий. То есть, он возвратит данные как только в сокете будет хоть один байт. Так как там есть цикл, то там будет блокирование, пока с той стороны не закроют сокет (то есть, даже если все данные прибегут, то код все равно будет ждать закрытия сокета. Если сервер не закрывает сокет сразу, это может быть причиной подвисания.)

Теперь о испорченных данных. Метод Receive устроен так, что он будет возвращать данные произвольными порциями от 1 байта до ..., а тут спорный вопрос, возможно несколько килобайт (верю в 8килобайт), а может и сотни (я не достаточно хорошо знаю подсистему .NET). Но это не имеет значения. Важно то, что если с одной стороны отправлять порциями по 100 байт, то с другой стороны не объязательно будет читаться по 100 байт. может и по 20, 40 и другими.

А это важно, так как юникодная строка (какая она бы не была, utf-8 или ucs-16) не объязательно содержит один байт на символ и строка может разбиваться по средине символа. И вот тут будут проблемы. Но эту проблему легко решить - нужно прочитать все данные и только потом декодировать.

А вот с первой проблемой немного сложнее. Нужно знать "структуру данных". Например, данные могут читаться до перевода строк или размер данных известен.

READ ALSO
Интеграция Web API и OAuth 2.0 с сайтом, написанным с использованием Razor

Интеграция Web API и OAuth 2.0 с сайтом, написанным с использованием Razor

ЗдравствуйтеЕсть сайт, написанный с использованием синтаксиса Razor

223
админ панель asp.net mvc c#

админ панель asp.net mvc c#

Ситуация такая, собираюсь сделать админ панель для создания объектов: новых и редактирования старых, админ будет только один, то есть я не собираюсь...

764
Реализация дерева C#

Реализация дерева C#

Помогите пожалуйста с алгоритмомУ меня есть список такой структуры:

392