I have found a few examples online of how to write a socket server for a chat application. I pieced a few together and got it working great in a console application. I have since tried pushing it to a Winforms application and run into a small snag.

When I F5 my app (or build and launch the exe), the form disappears when I instantiate my ChatServer class. The server does indeed run (I can connect to it with clients and chat 'till the cows come home), but I want the form to remain visible as it has a large textbox I'm using to write events to.

my form1.cs file is nothing more than this

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

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

        private void Form1_Load(object sender, EventArgs e)
        {
            txtConsole.Text = "Starting Chat\r\n";
            StartChat();
        }
        private void StartChat()
        {            
            ChatServer server = new ChatServer(this);
        }
    }
}

There is nothing in my ChatServer class that is telling my form1 object to hide the form...any idea what would cause the form to disappear? If I comment out ChatServer server = new ChatServer(this); the form shows up with my large text box (but obviously the chat server doesn't start).

Well without knowing more about chatserver, as a class, Im going to guess it never was told to.. thats what debugging is for.

...Im going to guess it never was told to..

It never was told to what...not disappear?

I've put in break points in my ChatServer class at the initializer method and when I debug, the form is already gone.

I've also tried using obj.Show() (where obj is my form1 instance being passed to ChatServer) and that causes my app to crash. I really didn't want to post ChatServer.cs in here because I don't want to bog you down with a lot of code, but if you think that'd help, here it is.

Credit goes to the tutorial found here: http://www.dreamincode.net/forums/showtopic33396.htm for the guidance in putting this together.

Again, I'm not sure why my form is disappearing when the program loads. There's nothing in the ChatServer class that should cause this.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
using Chat = System.Net;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;


namespace WindowsChat
{
    class ChatServer
    {
        System.Net.Sockets.TcpListener chatServer;
        public static Hashtable nickName;
        public static Hashtable nickNameByConnect;

        public ChatServer(Form1 obj)
        {
            nickName = new Hashtable(100);
            nickNameByConnect = new Hashtable(100);
            // set local ip to listen on
            IPAddress localip = IPAddress.Parse("192.168.1.154");

            //create chat server var using new arguments
            chatServer = new System.Net.Sockets.TcpListener(localip, 4296);
            //MessageBox.Show("chat starting");
            obj.txtConsole.Text += "Chat Server Started\r\n";
            

            while (true)
            {
                // start the server
                chatServer.Start();
                // check pending connections
                if (chatServer.Pending())
                {
                    // if pending create new connection
                    Chat.Sockets.TcpClient chatConnection = chatServer.AcceptTcpClient();
                    DateTime now = DateTime.Now;
                    //write message to console to indicate new connection
                    obj.txtConsole.Text += "New Client Connected - " + now.ToString("MM/dd/yyyy h:mm:ss tt") + "\r\n";
                    DoCommunicate comm = new DoCommunicate(chatConnection,obj);
                }
            }
        }

        public static void SendMsgToAll(string nick, string msg)
        {
            StreamWriter writer;
            // craete tcp client array
            Chat.Sockets.TcpClient[] tcpClient = new System.Net.Sockets.TcpClient[ChatServer.nickName.Count];
            //populate the array
            ChatServer.nickName.Values.CopyTo(tcpClient, 0);
            // loop through the clients and write messages to them
            for (int cnt = 0; cnt < tcpClient.Length; cnt++)
            {
                try
                {
                    if (msg.Trim() == "" || tcpClient[cnt] == null)
                        continue;
                    writer = new StreamWriter(tcpClient[cnt].GetStream());
                    writer.WriteLine(nick + ":" + msg);
                    // flush the writer to make sure everything is written
                    writer.Flush();
                    //dispose the writer
                    writer = null;
                }
                catch (Exception e)
                {
                    string str = (string)ChatServer.nickNameByConnect[tcpClient[cnt]];
                    ChatServer.SendSystemMessage("**" + str + "** Has Left The Room.");
                    ChatServer.nickName.Remove(str);
                    ChatServer.nickNameByConnect.Remove(tcpClient[cnt]);
                }
            }
        }

        public static void SendSystemMessage(string msg)
        {
            //create another streamwriter
            StreamWriter writer;
            // create tcpclient array
            Chat.Sockets.TcpClient[] tcpClient = new System.Net.Sockets.TcpClient[ChatServer.nickName.Count];
            //populate the array
            ChatServer.nickName.Values.CopyTo(tcpClient, 0);
            for (int i = 0; i < tcpClient.Length; i++)
            {
                try
                {
                    if (msg.Trim() == "" || tcpClient[i] == null)
                        continue;
                    writer = new StreamWriter(tcpClient[i].GetStream());
                    writer.WriteLine(msg);
                    writer.Flush();
                    writer = null;
                }
                catch (Exception e)
                {
                    ChatServer.nickName.Remove(ChatServer.nickNameByConnect[tcpClient[i]]);
                    ChatServer.nickNameByConnect.Remove(tcpClient[i]);
                }
            }
        }
    }
}

K, dont run the code in the load - because you arent threading it, the form will never show until you close the socket and end your chat server.

I don't fully understand the threading thing quite yet but I have put my ChatServer instantiation inside a button click method (so it doesn't run on the load per your suggestion).

when I click the button however, the app crashes.

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

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

        private void Form1_Load(object sender, EventArgs e)
        {
            
        }

        private void btnStartChat_Click(object sender, EventArgs e)
        {
            txtConsole.Text = "Starting Chat\r\n";
            ChatServer server = new ChatServer(this);
        }
    }
}

Define crashes - how? in what way? whats the message? what did debugging show you?

by crashes I mean stopped responding.

I tried putting in into a different thread (at least as much I know about threading anyway) and now the form doesn't disappear and the app doesn't crash (stop responding), however, it doesn't appear that the server is actually started as when I try to connect with a client, there is no server available. I'm sorry for the newbness of my questions, but as I said before, I'm still quite new to threading:

does this look like I"m on the right track?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

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

        private void Form1_Load(object sender, EventArgs e)
        {
            
        }

        private void btnStartChat_Click(object sender, EventArgs e)
        {
            txtConsole.Text = "Starting Chat\r\n";
            Thread chatThread = new Thread(new ThreadStart(StartChat));
        }

        private void StartChat()
        {
            ChatServer server = new ChatServer(this);
        }
    }
}

OK, so it hasnt crashed. Its in a loop, which is exactly what you told it to do.

Your thread code looks OK on face value.. does it do what you wanted is more important!

....does it do what you wanted is more important!

unfortunately no. The chat server appears to start correctly and my "Starting Chat" gets put into the textbox and it doesn't appear that I'm 'getting stuck in a loop' as the app stays responsive. However, when I try to connect with my chat client, it can't find the server which indicates to me that the server isn't actually starting. Another indication that it isn't actually starting is line 33 within ChatServer.cs which is supposed to write "Chat Server Started" to my text box and that isn't happening either.

any ideas?

Well being in a thread it cant just write to your form, so Id have expected it to crash out and say so.

hmm...it doesn't appear to be throwing any errors.

Any way I can pass information from one thread to the other? But more importantly, any way I can make the chat server start with what you see in my code?

I realize this is a tall order and I do appreciate your time...I am trying :P

I was missing my Thread.Start() method....now I"m getting the errors.

I'm reading up on making thread-safe calls but any light you can shed would be greatly appreciated.

thanks again,

Burr

I got this working.

Thanks Liz for the assistance.

I've actually now put it into a windows service using the same technique and it works just as it should.

Would you suggest doing something different with the ChatServer class. I know using while(true) is generally bad practice...

I used a boolean flag, so I could do while (keeprunning) , that way I can set keeprunning to false outside the loop and the thread finishes cleanly.

This article has been dead for over six months. Start a new discussion instead.