Socket-программирование - PullRequest
       9

Socket-программирование

0 голосов
/ 01 апреля 2009

Хорошо, ребята, я сломал свой маленький мозг и не смог найти решение. Проблема в том, что я могу вызвать begin-receive один раз, но после этого я не могу найти подходящую технику, с помощью которой метод можно вызывать снова и снова. Следовательно, хотя соединение устанавливается, сообщения могут быть получены только один раз и не более после этого. Пожалуйста, помогите, потому что это ужасно срочно. Я записываю весь код здесь.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.IO;
using.System.Threading;

namespace WindowsApplication1
{
public partial class lanmessenger : Form
{

    Socket client;
    Socket newSock, server, hostSock, remote;


    byte[] receiveBuffer = new byte[1024];
    byte[] sendBuffer = new byte[1024];

    String dataEntered;

    StringBuilder textbox1, receivedData, sb;

    IPEndPoint serverIP, clientIP;

    [DllImport("user32.dll")]
    static extern bool HideCaret(IntPtr hWnd);

    Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    IPAddress localaddress = IPAddress.Parse("127.0.0.1");


    public void Receive()
    {
        if (remote.Connected)
            remote.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, System.Net.Sockets.SocketFlags.None, new AsyncCallback(OnReceivingData), remote);
        else
            return;
    }


    void OnReceivingData(IAsyncResult ar)
    {

        remote = (Socket)ar.AsyncState;

        int recv = remote.EndReceive(ar);

        receivedData = new StringBuilder(Encoding.ASCII.GetString(receiveBuffer, 0, recv));
        //MessageBox.Show(receivedData.ToString(), "received", MessageBoxButtons.OK);

        sb = new StringBuilder(this.textBox1.Text);
        sb.AppendLine(receivedData.ToString());

        if (textBox1.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate { this.textBox1.Text = sb.ToString(); });

        }
        //Receive();     


        return;
    }



    private void Accepted(IAsyncResult ar)
    {
        server = (Socket)ar.AsyncState;
        client = server.EndAccept(ar);
        /*if (client.Connected)
            MessageBox.Show("client connected");*/

        try
        {
            client.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, System.Net.Sockets.SocketFlags.None, new AsyncCallback(OnReceivingData), client);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("arguments incorrect in begin-receive call", "Error", MessageBoxButtons.OK);
        }
        catch (SocketException)
        {
            MessageBox.Show("error in accessing socket while receiving", "Error", MessageBoxButtons.OK);
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while receiving", "Error", MessageBoxButtons.OK);
        }
        catch (Exception)
        {
            MessageBox.Show("error while receiving", "Error", MessageBoxButtons.OK);
        }

    }

    public void FirstEndPoint()
    {
        newSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientIP = new IPEndPoint(localaddress, 5555);

        newSock.Bind(clientIP);
        newSock.Listen(100);

        try
        {
            newSock.BeginAccept(new AsyncCallback(Accepted), newSock);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("Error in arguments while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (SocketException)
        {
            MessageBox.Show("Error accessing socket while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (InvalidOperationException)
        {
            MessageBox.Show("Invalid operation while using begin-accept", "Error", MessageBoxButtons.OK);
        }
        catch (Exception)
        {
            MessageBox.Show("Exception occurred while using begin-accept", "Error", MessageBoxButtons.OK);
        }
    }

    public void CreateThread()
    {
        Thread FirstThread = new Thread(new ThreadStart(FirstEndPoint));
        FirstThread.Start();
    }

    public lanmessenger()
    {
        InitializeComponent();
        CreateThread();   

    }

    void OnSendingData(IAsyncResult ar)
    {
        Socket socket = (Socket)ar.AsyncState;
        int AmtOfData = socket.EndSend(ar);
        //MessageBox.Show(AmtOfData.ToString());

        return;
    }

    public void SendingData(Socket sock, String data)
    {
        textbox1.AppendLine(this.textBox2.Text);

        if (textBox1.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate { this.textBox1.Text = textbox1.ToString(); });
        }


        if (textBox2.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate { this.textBox2.Text = "\0"; });
        }


        sendBuffer = Encoding.ASCII.GetBytes(data);


        try
        {
            sock.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, new AsyncCallback(OnSendingData), sock);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("arguments incorrect in begin-send call", "Error", MessageBoxButtons.OK);
        }
        catch (SocketException ex)
        {
            String str1 = "error in accessing socket while sending" + ex.ErrorCode.ToString();
            MessageBox.Show(str1, "Error", MessageBoxButtons.OK);
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while sending", "Error", MessageBoxButtons.OK);
        }
        catch (Exception)
        {
            MessageBox.Show("error while sending", "Error", MessageBoxButtons.OK);
        }
    }

    private void OnClientConnect(IAsyncResult ar)
    {
        Socket sock = (Socket)ar.AsyncState;

        try
        {
            sock.EndConnect(ar);
            if (sock.Connected)
                MessageBox.Show("connected");

        }
        catch (SocketException ex)
        {
            MessageBox.Show("Error in accessing socket while using end-connect" + ex.ErrorCode.ToString(), "Error", MessageBoxButtons.OK);
            return;

        }

        if ((sock.Connected) && (dataEntered != ""))
        {
            SendingData(sock, dataEntered);
        }

    }



    private void button1_Click(object sender, EventArgs e)
    {

        HideCaret(this.textBox1.Handle);

        textbox1 = new StringBuilder(this.textBox1.Text);
        dataEntered = this.textBox2.Text;
        hostSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        serverIP = new IPEndPoint(localaddress, 5555);


        try
        {
            hostSock.BeginConnect(serverIP, new AsyncCallback(OnClientConnect), hostSock);
        }
        catch (ArgumentException)
        {
            MessageBox.Show("Error in arguments while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }
        catch (SocketException)
        {
            MessageBox.Show("Error in accessing socket while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }
        catch (ObjectDisposedException)
        {
            MessageBox.Show("socket closed while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }
        catch (InvalidOperationException)
        {
            MessageBox.Show("Invalid operation while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }

        catch (Exception)
        {
            MessageBox.Show("Exception while using begin-connect", "Error", MessageBoxButtons.OK);
            return;
        }

    }

}

}

Ответы [ 2 ]

2 голосов
/ 01 апреля 2009

Прежде всего, вы можете пометить свой вопрос некоторыми более подходящими тегами. Кроме того - поскольку это извлечено из документации MSDN для асинхронного обмена сообщениями TCP-клиентов, вы можете снова обратиться к своей документации.

(В вашем локальном URL-адресе справки VS: Пример сокета MSDN для асинхронного клиента )

Вы не упомянули, почему запуск новой асинхронной операции приема не удался в вашем методе обратного вызова - какую ошибку вы видите?

Если ваше сообщение было успешно получено и обработано в асинхронном обратном вызове, вы можете оттуда снова вызвать свой прием (который вы закомментировали). Имейте в виду, что если вы повторно используете свой объект состояния (в вашем случае удаленный), вам необходимо очистить буфер и все другие объекты, которые в нем сохраняются.

В вашем методе Receive вы должны инициализировать ваш объект состояния и снова подготовить его к новой асинхронной операции приема.

Также: обратный вызов приема, который я использовал ранее. Некоторые из них относятся к приложению, над которым я работал (например, добавление в очередь сообщения в базовом классе, из которого оно было получено), и оно было довольно быстрым и грязным, но это может помочь.

    private void ReceiveCallback(IAsyncResult ar)
    {
        int bytesRead = 0;

        try
        {
            // receive finished
            if (ar.IsCompleted)
            {
                TcpIpState stateObject = (TcpIpState)ar.AsyncState;
                bytesRead = stateObject.TcpIpSocket.EndReceive(ar, out seSocketError);
                if (bytesRead > 0)
                {
                    foreach (ArraySegment<byte> asBuffer in stateObject.Buffer)
                    {

                            stateObject.SBuilder.Append(
                                Encoding.ASCII.GetChars(
                                asBuffer.Array,
                                0,
                                asBuffer.Count));

                    }
                    // Let the owner object know of the received message
                    base.EnqueueMessage(new TcpIpMessage(stateObject.SBuilder.ToString()));

                    // Start a new receive operation
                    stateObject.SBuilder = new StringBuilder();
                    stateObject.Buffer.Clear();
                    stateObject.Buffer.Add(new ArraySegment<byte>(new byte[_bufferSize]));
                    stateObject.TcpIpSocket.BeginReceive(
                        stateObject.Buffer,
                        SocketFlags.None,
                        new AsyncCallback(ReceiveCallback),
                        stateObject);
                }
                else
                {
                    OnDisconnected(this, new Exception("Bytes returned are 0"));
                    Disconnect();
                }
            }
        }
        catch (Exception e)
        {
            // Something has gone wrong on a low level portion
            OnDisconnected(this, e);
            Disconnect();
        }
    }
1 голос
/ 01 апреля 2009

Стандартный способ выполнения асинхронного чтения сокетов в .NET - это многократный вызов BeginReceive в конце обратного вызова приема. Похоже, у вас есть необходимый вызов для Receive закомментированного. Я просто ожидал, что этот звонок будет рада, и все должно работать нормально. Я не провёл самый подробный анализ вашего кода, поэтому я могу что-то упустить, но это определенно первое, что нужно попробовать. Может быть, если вы подробно опишите проблему, с которой вы столкнулись при реализации этого метода, мы могли бы помочь вам немного подробнее.

В качестве (незначительного) побочного замечания я настоятельно рекомендую использовать класс TcpClient, если вы осуществляете TCP-связь в .NET, как вы это делаете. Это значительно упрощает работу с сокетами нижнего уровня и, как правило, делает общение по протоколу TCP более дружественным для программиста! Конечно, асинхронное чтение «цикла» было бы почти таким же. Также на многих других сайтах (включая SO) имеется множество документации по MSDN и учебным пособиям / фрагментам кода о том, как правильно использовать класс TcpClient для различных целей (это становится немного сложнее, когда вы хотите выполнить многопоточность или повторно использовать TcpClient объект).

...