1

I am making a chat service for a game,

I am using a TCP listener an client for the account information, some sort of login service. I'm wondering if i can keep the socked the client connected to the server with, to check if he is still online, and keep sending him messages if he has new messages.

I already tried making a list of sockets for the login queue, but it disconnected the previous socket to to server as soon as i accepted a new socket.

byte[] usernameByte = new byte[100];
int usernameRecieved = s.Receive(usernameByte);
//guiController.setText(System.DateTime.Now + " Recieved Login...");

byte[] passByte = new byte[100];
int passRecieved = s.Receive(passByte);
//guiController.setText(System.DateTime.Now + " Recieved Password...");

string username = "";
string password = "";

for (int i = 0; i < usernameRecieved; i++)
     username += (Convert.ToChar(usernameByte[i]));

for (int i = 0; i < passRecieved; i++)
     password += (Convert.ToChar(passByte[i]));

if (DomainController.getInstance().checkAccount(username, password))
{
    ASCIIEncoding asen = new ASCIIEncoding();
    s.Send(asen.GetBytes("true"));
    s.Send(asen.GetBytes("U are succesfully logged in, press enter to continue"));
    guiController.setText(serverName,System.DateTime.Now+"");
    guiController.setText(serverName, "Sent Acknowledgement - Logged in");
}
else
{
    ASCIIEncoding asen = new ASCIIEncoding();
    s.Send(asen.GetBytes("false"));
    s.Send(asen.GetBytes("U are NOT logged in, press enter to continue"));
    guiController.setText(serverName, System.DateTime.Now + "");
    guiController.setText(serverName, "\nSent Acknowledgement - Not logged in");
}

This is the code i currently use to check the account information the user send me. Right after i send this the user dropd the connection and i move on to the next one.

I have tried making 1 list of seperate sockets and processing them one by one, but that failed because the previous socket's connection dropped, even tho it were 2 different machines that tried to connect.

Does anyone have a sollution / a way to save sockets, that I can use to make the program keep all the connections alive? so i can send a message from user 1 to user 2, and just use the socket they connected with? or do i need to add an id every time they make a connection?

EDIT

The client Code: (this is just a test client)

while (true)
{
TcpClient tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
tcpclnt.Connect("xx.xxx.xxx.xx", 26862);
// use the ipaddress as in the server program

while(!(checkResponse(tcpclnt.GetStream())))
{
     Thread.Sleep(1000);
}

Console.WriteLine("Connected");

Console.Write("Enter the string to be transmitted : ");

String str = Console.ReadLine();
if (str == "")
{
    str = " ";
}
                    
Stream stm = tcpclnt.GetStream();

ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(str);


Console.WriteLine("Transmitting.....");

stm.Write(ba, 0, ba.Length);

Console.Write("Enter the string to be transmitted : ");

String str2 = Console.ReadLine();
if (str2 == "")
{
   str2 = " ";
}

Stream stm2 = tcpclnt.GetStream();

ASCIIEncoding asen2 = new ASCIIEncoding();
byte[] ba2 = asen2.GetBytes(str2);


Console.WriteLine("Transmitting.....");

stm.Write(ba2, 0, ba2.Length);
if (str == "false")
{
    blijvenWerken = false;
}
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);

for (int i = 0; i < k; i++)
Console.Write(Convert.ToChar(bb[i]));

byte[] bb2 = new byte[100];
int k2 = stm.Read(bb2, 0, 100);
Console.Write("\n");
for (int i = 0; i < k2; i++)
Console.Write(Convert.ToChar(bb2[i]));

Console.WriteLine("\n");

tcpclnt.Close();
Thread.Sleep(1000);
}

Server getting the sockets: This bit of code is on the loginserver, its because i can only accept 1 socket every time to keep the connection alive, that i put queueCount on a maximum of 1. I want to be able to make a list of Sockets that i accepted to add to a User account.

while (loginServerOn)
{
    if (queueCount < 1)
    {
        if (loginServer.getLoginListener().Pending())
        {
            loginQueue.Add(loginServer.getSocket());
            ASCIIEncoding asen = new ASCIIEncoding();
            Socket s = loginQueue.First();
            try
            {
                s.Send(asen.GetBytes("true"));
                queueCount++;
            }
            catch
            {
                loginQueue.Remove(s);
            }
        }
    }
}

The function that returns the accepted socket.

public Socket getSocket()
{
    return myList.AcceptSocket();
}

EDIT: Essence of the question

I want to add the socked or client recieved to my Account object, so every connection has an Account its linked to, when i want to send a message to a certain account, it should send a message to the socked or client bound to that account, can you help/show me how i can achieve this?

Community
  • 1
  • 1
Jonathan
  • 324
  • 1
  • 6
  • 18
  • That code looks plausible so far. What's the rest of your code look like where you listen for the socket on the server? It sounds like either your client or server is closing when it shouldn't be. – David Jan 15 '13 at 21:24
  • @David i edited some some more code into the project. – Jonathan Jan 15 '13 at 22:15

2 Answers2

1

This is still c# and sockets but my approach is different to yours.

I went with the concept of a "connectedCleint" which is similar in purpose to what you've called an account.

I have a class called ServerTerminal which is responsible for accepting and top level management of socket connections. In this i've got:

 public Dictionary<long, ConnectedClient> DictConnectedClients =
        new Dictionary<long, ConnectedClient>();

So this is my list of connected clients indexed by the sockethandle.

To accept connections i've got a routine:

public void StartListen(int port)
    {
        socketClosed = false;
        IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);

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

        //bind to local IP Address...
        //if ip address is allready being used write to log
        try
        {
            listenSocket.Bind(ipLocal);
        }
        catch (Exception excpt)
        {
            // Deal with this.. write your own log code here ?
            socketClosed = true;

            return;
        }
        //start listening...

        listenSocket.Listen(100); // Max 100 connections for my app

        // create the call back for any client connections...
        listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);

    }

So when a client connects it then fires off:

private void OnClientConnection(IAsyncResult asyn)
    {
        if (socketClosed)
        {
            return;
        }

        try
        {
            Socket clientSocket = listenSocket.EndAccept(asyn);

            ConnectedClient connectedClient = new ConnectedClient(clientSocket, this, _ServerTerminalReceiveMode);

            //connectedClient.MessageReceived += OnMessageReceived;
            connectedClient.Disconnected += OnDisconnection;
            connectedClient.dbMessageReceived += OndbMessageReceived;

            connectedClient.ccSocketFaulted += ccSocketFaulted;

            connectedClient.StartListening();

            long key = clientSocket.Handle.ToInt64();
            if (DictConnectedClients.ContainsKey(connectedClient.SocketHandleInt64))
            {
                // Already here - use your own error reporting..
            }

            lock (DictConnectedClients)
            {
                DictConnectedClients[key] = connectedClient;
            }

            // create the call back for any client connections...
            listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);

        }
        catch (ObjectDisposedException excpt)
        {
            // Your own code here..
        }
        catch (Exception excpt)
        {
            // Your own code here...
        }

    }

The crucial part of this for you is:

            // create the call back for any client connections...
            listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);

This sets up the serverterminal to receive new connections.

Edit: Cut down version of my connectedclient:

public class ConnectedClient
{
    private Socket mySocket;
    private SocketIO mySocketIO;

    private long _mySocketHandleInt64 = 0;


    // These events are pass through; ConnectedClient offers them but really
    // they are from SocketIO

    public event TCPTerminal_ConnectDel Connected
    {
        add
        {
            mySocketIO.Connected += value;
        }
        remove
        {
            mySocketIO.Connected -= value;
        }
    }

    public event TCPTerminal_DisconnectDel Disconnected
    {
        add
        {
            mySocketIO.Disconnected += value;
        }
        remove
        {
            mySocketIO.Disconnected -= value;
        }
    }

    // Own Events

    public event TCPTerminal_TxMessagePublished TxMessageReceived;

    public delegate void SocketFaulted(ConnectedClient cc);
    public event SocketFaulted ccSocketFaulted;

    private void OnTxMessageReceived(Socket socket, TxMessage myTxMessage)
    {
     // process your message
    }



    private void OnMessageSent(int MessageNumber, int MessageType)
    {
    // successful send, do what you want..
    }





    public ConnectedClient(Socket clientSocket, ServerTerminal ParentST)
    {
        Init(clientSocket, ParentST, ReceiveMode.Handler);
    }

    public ConnectedClient(Socket clientSocket, ServerTerminal ParentST, ReceiveMode RecMode)
    {
        Init(clientSocket, ParentST, RecMode);
    }

    private void Init(Socket clientSocket, ServerTerminal ParentST, ReceiveMode RecMode)
    {
        ParentServerTerminal = ParentST;
        _myReceiveMode = RecMode;

        _FirstConnected = DateTime.Now;
        mySocket = clientSocket;
        _mySocketHandleInt64 = mySocket.Handle.ToInt64();
        mySocketIO = new SocketIO(clientSocket, RecMode);

        // Register for events
        mySocketIO.TxMessageReceived += OnTxMessageReceived;
        mySocketIO.MessageSent += OnMessageSent;
        mySocketIO.dbMessageReceived += OndbMessageReceived;

    }


    public void StartListening()
    {
        mySocketIO.StartReceiving();
    }

    public void Close()
    {
        if (mySocketIO != null)
        {
            mySocketIO.Close();
            mySocketIO = null;
        }

        try
        {
            mySocket.Close();
        }
        catch
        {
            // We're closing.. don't worry about it
        }
    }

    public void SendMessage(int MessageNumber, int MessageType, string Message)
    {
        if (mySocket != null && mySocketIO != null)
        {
            try
            {
                mySocketIO.SendMessage(MessageNumber, MessageType, Message);
            }
            catch
            {
                // mySocketIO disposed inbetween check and call
            }
        }
        else
        {
            // Raise socket faulted event
            if (ccSocketFaulted != null)
                ccSocketFaulted(this);
        }
    }


}

}

Some useful links:

This is where I started: http://vadmyst.blogspot.com.au/2008/01/how-to-transfer-fixed-sized-data-with.html

http://vadmyst.blogspot.com.au/2008/03/part-2-how-to-transfer-fixed-sized-data.html

And..

C# Sockets and Multithreading

Cause a connected socket to accept new messages right after .BeginReceive?

http://nitoprograms.blogspot.com.au/2009/04/tcpip-net-sockets-faq.html

http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod

I can't post my entire solution just now; there is a flaw in my server code I need to debug; plus there are parts which my employer may not want published. But i based my code on what Vadym had for variable length messages.

Community
  • 1
  • 1
andrew
  • 1,184
  • 3
  • 19
  • 28
  • Hey andrew, thanks for the help so far, but can you please show me your ConnectedClient class? maybe post the full class so i can take a look at whats important there? Thanks in advance – Jonathan Jan 16 '13 at 01:33
  • The part about the Dictionary i don't realy understand, can i just add that ConnectedClient to my account? or is the dictionary nessesary? – Jonathan Jan 16 '13 at 01:35
  • Also, to connect with my client, do i need to reprogram my client as well? to match this code? could you also show me an example of that please, thanks for the help – Jonathan Jan 16 '13 at 01:39
  • My full connectedclient is 1100 lines long but i'll post some of the important parts. Also my connected client doesn't actually handle the socket IO; it's just the manager for the socket connection. I've got a socketIO class that handles the actual IO with socket. I assumed "account" was details like name, password and perhaps related connection info; i'm using a dictionary in serverterminal but could have used a list instead. Chose dict 'cause if i'm given a sockethandle in a call back, I can find the client. – andrew Jan 16 '13 at 05:59
  • For the client, I used the same socketio class I developed - essentially it handles open, close, sending, receiving and errors; and publishes events when those situations occur. My ConnectedClient and ClientTerminal classes subscribe to those events and react as needed. – andrew Jan 16 '13 at 06:00
  • On your client code - assuming the client is only talking to the one server, it doesn't need to maintain a list like a serverterminal - just connect the socket, if all ok, use it until it faults/disconnects. Other things you may want to consider: auto-reconnects, heartbeat messages as a keepalive & test, how long is a message - how do you know if you've got some, all or, all + some of another message when you receive data – andrew Jan 16 '13 at 06:09
  • _ServerTerminalReceiveMode what does this actually do? – Jonathan Jan 16 '13 at 12:26
  • Hey, i know this is a lot to ask, but could you please post the code of all the linking classes, because it gives a lot of errors, and i don't realy know what to program there :p – Jonathan Jan 16 '13 at 13:36
  • Is it possible to upload a .svn file somewhere so i can take a look, just so i can understand the code better, thanks for all the help already. – Jonathan Jan 16 '13 at 20:28
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/22867/discussion-between-andrew-and-jonathan) – andrew Jan 17 '13 at 02:27
  • thanks, i just need some sort of way to save my connected peoples, so i can send them a message in a verry easy way. once i have that, i should be set to continue. And so i can check for a disconnect. – Jonathan Jan 17 '13 at 19:50
  • Is there a way you can help me set that system up? or would that be too much work? – Jonathan Jan 17 '13 at 19:51
  • Next few weeks i'll be flat out and no-where near my computer. Read up on Vadym's code and look to replicate what I did - create a SocketIO class that is responisbile for making a connection, handling disconnects; sending and receiving - but nothing else. Then a "connectedClient" class which handles your user's connections; and a receiverterminal class which the client uses. And lastly a serverterminal class to be the overall manager of connectedClients. if you can PM me with your email perhaps I can send some of my code. – andrew Jan 18 '13 at 00:15
  • No PM on SO; leave contact info in your profile and i'll contact you from there.. – andrew Jan 18 '13 at 00:17
  • i wrote my e-mail in the chat you made. – Jonathan Jan 18 '13 at 00:55
  • thanks for all the help already, i think i got the sending and recieving right now, but do i need to make those handlers as well on the client side? – Jonathan Jan 18 '13 at 00:56
  • i don't realy know how to check for disconnects, and you have to help me with my connected clients, but i think i'm on the right path now, thanks :) – Jonathan Jan 18 '13 at 00:56
  • The e-mail keeps bugging, the i think i'm almost there tho, i only need help with sending a message from the server to the client, any more help would be appreciated, thanks a lot already. – Jonathan Jan 20 '13 at 00:23
0

When a server gets ready to accept TCP connections, it creates a new TCP socket, Bind() it to a port and uses the Listen() method. When a connection request comes in, the Listen() method returns a new socket that the server and client use for communication. The server and client can pass data back and forth using Send() and Receive() at this point. If the client disconnects, the server's Receive() terminates with 0 bytes of data.

If you want to wait for another connection request once you've accepted the first connection (i.e., while you are interacting with the first client) this can be done. At this point, you'll need to use something like threads or asynchronous methods so you can handle more than one connection. Basically, you will be able to Accept() connection requests from your listening socket.

Mike

mikebk
  • 95
  • 7
  • This is not realy an answer to my question, below in this comment is a short summary of the question. I want to add the socked or client recieved to my Account object, so every connection has an Account its linked to, when i want to send a message to a certain account, it should send a message to the socked or client bound to that account, can you help/show me how i can achieve this? – Jonathan Jan 15 '13 at 23:08
  • I'd suggest taking a look at Andrew's response. – mikebk Jan 16 '13 at 14:33