views:

839

answers:

2

Ok guys I've racked my little brain and have been unable to find a solution. The problem here is that I am being able to call begin-receive once, but after that I am unable to find a proper technique by which the method can be called again and again. Consequently although a connection is being made,messages can be received just once and no more after that.. Please help because it is terribly urgent.Thanks a ton. I am putting down the entire code here.

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  A: 

First of all, you may want to tag your question with some more appropriate tags. Also - since this is pulled from the MSDN documentation for asynchronous TCP client messaging, you may want to refer again to your documentation there.

(In your local VS Help URL: MSDN Asynchronous Client Socket Example)

You didn't mention why starting a new asynchronous Receive operation fails in your callback method - what error are you seeing?

If your message is received successfully and processed in your Asynchronous callback, you can call your Receive again from there (which you have commented out). Keep in mind that if you reuse your state object (remote in your case), you'll need to clear out the buffer and any other objects that persist in it.

In your Receive method, you should initialize your state object and prepare it again for the new asynchronous receive operation.

Also: a Receive Callback that I've used previously. Some of it is specific to the app I was working on (such as enqueueing the message in the base class this was derived from), and it was fairly quick and dirty, but it may help.

    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();
        }
    }
Matt Jordan
For all others: http://msdn.microsoft.com/en-us/library/bew39x2a.aspx
Acron
+1  A: 

The standard way to do asynchronous socket reading in .NET is to repeatedly call BeginReceive at the end of the receive callback. You seem to have the necessary call to Receive commented out. Just uncommment that call and all should work fine, I would expect. I haven't taken the most detailed inspection of your code, so I may be missing something, but this is definitely the first thing to try. Maybe if you detail the exact problem you were experiencing implementing that method we could help you out a bit more.

As a (slight) side point, I would strongly recommend that you use the TcpClient class if you're doing TCP communication in .NET, as you clearly are. This simplifies a good deal of the lower-level socket stuff and generally makes TCP communication a lot more friendly to the programmer! The asynchronous reading "loop" would be much the same of course. Also, there's plenty of documentation on MSDN and tutorials/code snippets on many other sites (including SO) on how to use the TcpClient class properly for various purposes (it gets a bit trickier when you want to do multithreading or reuse the TcpClient object).

Noldorin
I concur on the TcpClient class. Makes life a lot simpler (and you can still access the low level socket using the Client property)
Matt Jordan