Question

Hi I've try to send and http request to a Shoutcast stream site and then read response, I've this two sources one is the main ( I've tested with wpf) and other is a little helper for socket... well all works, with localhost and other site but when I try to send a request to "209.9.238.6:6042" the header in response is never complete but truncked.

I've done a lot of test but nothing it works only with a Thread.sleep(200); between the send and receive look at (1), so it seems that listen() come too early and only a part is downloaded...

can You help me?

main.cs

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void connectionButton_Click(object sender, RoutedEventArgs e)
        {
            var url = "209.9.238.6:6042";

            var sockHelp = new SocketHelper(url);

            sockHelp.onConnect += sockHelp_onConnect;
            sockHelp.connect();

        }

        void testDebug(string str) {

            Action action = () => debugTxt.Text = str;
            Dispatcher.BeginInvoke(action);

        }

        void sockHelp_onConnect(object sender, SocketHelperEventArgs e)
        {

            var sockHelp = sender as SocketHelper;

            testDebug("Connected");

            var header = "";
            header+="GET / HTTP/1.0\r\n";
            header+="Accept: */*\r\n";
            header+="Host: 209.9.238.6\r\n";
            header+="Connection: close\r\n\r\n";

            sockHelp.onSend += sockHelp_onSend;
            sockHelp.sendAsync(Encoding.UTF8.GetBytes(header));

        }

        private void sockHelp_onSend(object sender, SocketAsyncEventArgs e)
        {
            var sockHelp = sender as SocketHelper;
            sockHelp.onReceive+=sockHelp_onReceive;

        //Thread.Sleep(200); (1)  uncomment this line... to make works

            sockHelp.listen();
        }

        void sockHelp_onReceive(object sender, SocketAsyncEventArgs arg_)
        {
            testDebug("Receiving");


            var t = Encoding.UTF8.GetString(arg_.Buffer);
            var idx = IndexOf(arg_.Buffer, new byte[] { 0x0d, 0x0a, 0x0d, 0x0a });

            if (idx < 0)
            {
                testDebug(Encoding.UTF8.GetString(arg_.Buffer));
                return ;
            }
            byte[] binBuff = new byte[idx + 1]; 
            System.Buffer.BlockCopy(arg_.Buffer, 0, binBuff, 0, idx + 1);
            testDebug(Encoding.UTF8.GetString(binBuff));
        }

        private int IndexOf(byte[] searchIn, byte[] searchFor)
        {
            if ((searchIn != null) && (searchIn != null))
            {
                if (searchFor.Length > searchIn.Length) return 0;
                for (int i = 0; i < searchIn.Length; i++)
                {
                    int startIndex = i;
                    bool match = true;
                    for (int j = 0; j < searchFor.Length; j++)
                    {
                        if (searchIn[startIndex] != searchFor[j])
                        {
                            match = false;
                            break;
                        }
                        else if (startIndex < searchIn.Length)
                        {
                            startIndex++;
                        }

                    }
                    if (match)
                        return startIndex - searchFor.Length;
                }
            }
            return -1;
        }

    }


}

helper.cs

namespace TestSocket
{
    /// <summary>

    /// </summary>
    public class SocketHelperEventArgs : EventArgs
    {

        public SocketHelperEventArgs(SocketError se)
        {
            socketError = se;
        }
        public SocketHelperEventArgs() { }
        SocketError socketError;
        SocketAsyncEventArgs args;
    }


    public class SocketHelper
    {
        byte[] _buffer = new byte[1024*2];
        SocketAsyncEventArgs _args = new SocketAsyncEventArgs();

        readonly Socket _socket;

        public event EventHandler<SocketHelperEventArgs> onError;
        public event EventHandler<SocketHelperEventArgs> onConnect;

        public event EventHandler<SocketAsyncEventArgs> onReceive;
        public event EventHandler<SocketAsyncEventArgs> onSend;

        public SocketHelper(string url)
        {

            int port=0;
            string[] addressVector = url.Split(':');
            if (addressVector.Length == 1)
                port = 80;
            else
                port = int.Parse(addressVector[1]);

            _args.RemoteEndPoint = new DnsEndPoint(addressVector[0], port); ;

            _args.Completed += SocketAsyncEventArgs_Completed;


            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


        }


        public void listen()
        {
            _args.SetBuffer(_buffer, 0, _buffer.Length);     

            _socket.ReceiveAsync(_args);
        }


        public void connect()
        {

            bool completesAsynchronously = _socket.ConnectAsync(_args);

            if (!completesAsynchronously)
            {
                SocketAsyncEventArgs_Completed(_args.ConnectSocket, _args);

            }
        }


        public void sendAsync(byte[] data) {

            _args.SetBuffer(data, 0, data.Length);
            _socket.SendAsync(_args);
        }

        private void SocketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
        {

            // check for errors 
            if (e.SocketError != SocketError.Success)
            {

                if (onError != null) onError(this, new SocketHelperEventArgs(e.SocketError));

                CleanUp(e);
                return;
            }

            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Connect:
                    if (onConnect != null) onConnect(this, EventArgs.Empty as SocketHelperEventArgs);
                    break;
                case SocketAsyncOperation.Send:
                    if (onSend!= null) onSend(this, e);
                    break;
                case SocketAsyncOperation.Receive:
                    if (onReceive != null) onReceive(this,e);
                    break;
            }
        }

        private void CleanUp(SocketAsyncEventArgs e)
        {
            if (e.ConnectSocket != null)
            {
                e.ConnectSocket.Shutdown(SocketShutdown.Both);
                e.ConnectSocket.Close();
            }
        }



    }
}
Was it helpful?

Solution

You seem to assume that you will get the whole response in one read. That's not correct. You will get some data from the socket when data is available. You need to detect whether there's more data to come according to the application-level protocol - HTTP or ICY or whatever you are using, and, if so, re-arm the asynchronous read.

Right now you are consuming whatever happens to be in the socket receive buffer. Waiting seems to work just because more data piles up there after that timeout, but there's no guarantee you are getting everything.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top