Сокет считывает данные асинхронно с помощью специального терминатора сообщений - PullRequest
0 голосов
/ 09 марта 2009

Я должен подключиться через tcp к серверу, который завершает ответы с 0x4 вместо стандартного 0x0. Я хочу, чтобы все было просто и использовать синхронную отправку / получение из класса сокетов. Посылка работает, но прием блокируется бесконечно, потому что сервер не завершает сообщения с 0x0. Я не могу синхронно прочитать первый 0x4 и закрыть, потому что мне нужно держать соединение открытым, чтобы отправлять больше сообщений. Было бы здорово, если бы я мог просто читать данные в отдельном потоке, используя BeginReceive, но, похоже, ему все еще нужен терминатор 0x0. Я попытался передать буфер размера 1 в BeginRecieve, надеясь, что он вызовет мой делегат для каждого чтения символов, но, похоже, это не сработает. Он читает первый символ и останавливается.

Есть идеи?

Вот приложение

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;


namespace SocketTest
{
    public partial class SocketTestForm : Form
    {
        Socket socket;
        byte[] oneChar = new byte[1];

        public SocketTestForm()
        {
            InitializeComponent();
        }

        private void GetButton_Click(object sender, EventArgs e)
        {
            //connect to google
            IPHostEntry host = Dns.GetHostEntry("google.com");
            IPEndPoint ipe = new IPEndPoint(host.AddressList[0], 80);
            socket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(ipe);
            if( socket.Connected )
                Console.WriteLine("Connected");

            //write an http get header

            String request = "GET / HTTP/1.1\r\nHost: google.com\r\nConnection: Close\r\n\r\n";

            socket.Send(Encoding.ASCII.GetBytes(request));

            //read the response syncronously, the easy way...
            //but this does not work if the server does not return the 0 byte...

            //byte[] response = new byte[5000];
            //socket.Receive(response, response.Length, SocketFlags.None);
            //string res = Encoding.ASCII.GetString(response);
            //Console.WriteLine(res);

            //read the response async
            AsyncCallback onreceive = ByteReceived;
            socket.BeginReceive(oneChar, 0, 1, SocketFlags.None, onreceive, null);
        }

        public void ByteReceived(IAsyncResult ar)
        {
            string res = Encoding.ASCII.GetString(oneChar);
            if (res[0] == 0x4) ; //fire some event 
        }
    }
}

1 Ответ

2 голосов
/ 10 марта 2009

Завершение с 0x04 кажется сомнительным, но причина, по которой ваш код останавливается после одного байта, заключается в том, что вы запросили только один байт. Если вам нужен второй байт, вы должны спросить снова.

При изменении значения ByteReceived следующим образом вы получите все байты, пока не получите 0x04:

public void ByteReceived(IAsyncResult ar)
{
    string res = Encoding.ASCII.GetString(oneChar);
    if (res[0] == 0x4)
    {
       //fire some event 
    }
    else
    {
       AsyncCallback onreceive = ByteReceived;
       socket.BeginReceive(oneChar, 0, 1, SocketFlags.None, onreceive, null);
    }
}

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

Опять завершение 0x04 кажется сомнительным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...