tags:

views:

123

answers:

2

Ok, I studied a bit on asynchronous TCP network connection. I tried making one but failed. What I want to do is make sure the server or client is always ready to receive a chat and is able to send a chat any time. I do not want them to be on alternate mode.

e.g. Server Send while client waits to receive thus client can't send at that time. I do not want that!

Did this on Windows Application. Once I connected, the system resource just shot to 100% =/

Server Code

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 AsyncServerChat
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Socket g_server_conn;
        private byte[] g_bmsg;
        private bool check = false;
        private void Form1_Load(object sender, EventArgs e)
        {
            IPEndPoint local_ep = new IPEndPoint(IPAddress.Any, 9050);

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

            winsock.Bind(local_ep);

            winsock.Listen(5);

            winsock.BeginAccept(new AsyncCallback(Accept), winsock);
        }

        private void Accept(IAsyncResult iar)
        {
            Socket server_conn =(Socket) iar.AsyncState;

            g_server_conn = server_conn.EndAccept(iar);

            //label1.Text = "Connected. . .";

            while (g_server_conn.Connected && check == false)
            {
                g_bmsg = new byte[1024];
                check = true;
                g_server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), g_server_conn);
            }
        }

        private void Send(IAsyncResult iar)
        {
            Socket server_conn = (Socket)iar.AsyncState;

            server_conn.EndSend(iar);
        }

        private void Recieve(IAsyncResult iar)
        {
            Socket server_conn =(Socket) iar.AsyncState;

            server_conn.EndReceive(iar);

            if (g_bmsg.Length != 0)
            {
                label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
                check = false;
            }
        }

        private void sendButton_Click(object sender, EventArgs e)
        {
            string strmsg = textBox1.Text;
            byte[] bmsg= Encoding.ASCII.GetBytes(strmsg);

            g_server_conn.BeginSend(bmsg, 0, bmsg.Length, SocketFlags.None, new AsyncCallback(Send), g_server_conn);
        }
    }
}

Client

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;

namespace AsyncClientChat
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Socket g_client_conn;
        byte[] g_bmsg;
        private bool check = false;
        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void connectButton_Click(object sender, EventArgs e)
        {
            IPEndPoint remote_ep = new IPEndPoint(IPAddress.Parse(textBox1.Text), 9050);

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

            g_client_conn.BeginConnect(remote_ep, new AsyncCallback(Connect), g_client_conn);
        }

        private void Connect(IAsyncResult iar)
        {
            Socket client_conn =(Socket) iar.AsyncState;

            client_conn.EndConnect(iar);

            while (g_client_conn.Connected)
            {
                g_bmsg = new byte[1024];
                check = true;
                g_client_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), g_client_conn);
            }
        }

        private void Send(IAsyncResult iar)
        {
            Socket client_conn = (Socket)iar.AsyncState;

            client_conn.EndSend(iar);
        }

        private void Recieve(IAsyncResult iar)
        {
            Socket client_conn = (Socket)iar.AsyncState;

            client_conn.EndReceive(iar);

            if (g_bmsg.Length != 0)
            {
                label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
                check = false;
            }
        }
    }
}
A: 

Well, the problem is the while loop in client method Connect. Remove it because it loops infinitely raising CPU usage to 100% and it's useless.

BTW, you have another problems in your code:

  • CrossThread operation exception

For example in your Client.Recieve method you do:
label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
Actually, you're trying to set the label text from another thread (the one listening for received msgs) and this is not allowed;
Do something like this:

Create a Setter method for the label text:

private void SetLabelText(string txt)
{
    if (label1.InvokeRequired)
        label1.Invoke(new MethodInvoker(delegate { SetLabelText1(txt); }));
    else
        label1.Text = txt;
}

then use the setter instead of directly call label1.Text = ...:

SetLabelText(Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));

EDIT to answer to OP comment:

For a good and extensive explanation of what is a thread, look at its wikipedia page.

Anyway, in simple words, a running process contains one or more threads and these are part of code that can be executed concurrently.

Starting from your TCP example, using Socket.Receive instead of Socket.BeginReceive you would have blocked the execution on Socket.Receive() call (I mean the lines of code after the one containing Receive method wouldn't be reached) until something is received.

This because Socket.Receive method runs on the same thread of the following code, and on each thread, the code is executed sequentially (i.e. line by line).

Conversely, using Socket.BeginReceive, behind the scene a new thread is created. This thread likely calls and stops on Socket.Receive method, and once received something it calls the method passed as parameter.

This makes Socket.BeginReceive asynchronous, while Socket.Receive is synchronous, and this is why I knew ther was another thread (when you hear asynchronous word, is extremely probable that you are dealing with multi-threading)

Thus, when you change label.Text you are actually setting it from another thread: the one created by Socket.BeginReceive.

digEmAll
The reason why i made the mistake is because i have not learnt threading haha. Can explain to what are threads and how u know that is a different thread?
RSTYLE
Check my edit ;)
digEmAll
+1  A: 

I took a quick look at this code and I would start with the following suggestion.

Remove the looping from your Accept callback, just initiate the BeginReceive and let it be. Then in your Receive method, you can just initiate the next BeginReceive. This would apply for both the client and the server code, except of course for the client code you will remove the loop from your Connect callback method.

Then you should also watch out updating the UI controls from the callback methods, since the callback runs on the non-UI thread which can cause a host of problems. You should look at using Control.Invoke or Control.BeginInvoke to marshal a request back to the UI thread which can then update the controls.

Chris Taylor