Приложение службы чата

Я делаю чат-сервис для игры,

Я использую слушатель TCP клиента для информации об учетной записи, своего рода сервис входа в систему. Мне интересно, могу ли я оставить подключенный к серверу подключенный к серверу клиент, чтобы проверить, находится ли он все еще в сети, и продолжать отправлять ему сообщения, если у него есть новые сообщения.

Я уже пытался составить список сокетов для очереди входа, но он отключил предыдущий сокет от сервера, как только я принял новый сокет.

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");
}

Это код, который я сейчас использую, чтобы проверить информацию об учетной записи, которую пользователь отправил мне. Сразу после того, как я отправил это, пользователь сбросил соединение, и я перехожу к следующему.

Я попытался составить 1 список отдельных сокетов и обработать их один за другим, но это не удалось, потому что соединение с предыдущим сокетом было прервано, даже если это были две разные машины, которые пытались подключиться.

У кого-нибудь есть решение / способ сохранить сокеты, которые я могу использовать, чтобы программа поддерживала все соединения? так что я могу отправить сообщение от пользователя 1 к пользователю 2, и просто использовать сокет, с которым они связаны? или мне нужно добавить идентификатор каждый раз, когда они устанавливают соединение?

РЕДАКТИРОВАТЬ

Код клиента: (это всего лишь тестовый клиент)

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);
}

Сервер получает сокеты: этот бит кода находится на сервере входа в систему, потому что я могу принимать только 1 сокет каждый раз, чтобы поддерживать соединение, что я поставил queueCount максимум 1. Я хочу иметь возможность составить список Сокеты, которые я согласился добавить в учетную запись пользователя.

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);
            }
        }
    }
}

Функция, которая возвращает принятый сокет.

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

РЕДАКТИРОВАТЬ: Суть вопроса

Я хочу добавить полученную учетную запись или клиента, полученную в мой объект Учетная запись, поэтому каждое соединение имеет учетную запись, к которой она привязана. Когда я хочу отправить сообщение определенной учетной записи, оно должно отправить сообщение подключенному или клиенту, привязанному к этой учетной записи., можете ли вы помочь / показать мне, как я могу этого добиться?

2 ответа

Решение

Это все еще C# и сокеты, но мой подход отличается от вашего.

Я придерживался концепции "connectedCleint", которая по своему назначению похожа на то, что вы называете учетной записью.

У меня есть класс с именем ServerTerminal, который отвечает за принятие и управление уровнями соединений с сокетами. В этом я получил:

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

Итак, это мой список подключенных клиентов, проиндексированных дескриптором сокета.

Чтобы принимать соединения, у меня есть процедура:

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);

    }

Поэтому, когда клиент подключается, он отключается:

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...
        }

    }

Важнейшая часть этого для вас:

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

Это устанавливает серверный терминал для получения новых соединений.

Изменить: Сократить версию моего подключенного клиента:

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);
        }
    }


}

}

Несколько полезных ссылок:

Вот где я начал: 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

А также..

C# сокеты и многопоточность

Заставить подключенный сокет принимать новые сообщения сразу после.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

Я не могу опубликовать все мое решение только сейчас; в коде моего сервера есть недостаток, который мне нужно отладить; плюс есть части, которые мой работодатель не хочет публиковать. Но я основал свой код на том, что имел Вадим для сообщений переменной длины.

Когда сервер готов принять TCP-соединения, он создает новый сокет TCP, связывает его с портом и использует метод Listen(). Когда приходит запрос на соединение, метод Listen() возвращает новый сокет, который сервер и клиент используют для связи. На этом этапе сервер и клиент могут передавать данные назад и вперед с помощью Send () и Receive(). Если клиент отключается, сервер Receive() завершает работу с 0 байтами данных.

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

Майк

Другие вопросы по тегам