客户端服务器应用程序在登录后关闭

时间:2020-01-31 00:49:51

标签: c# sockets client-server stack-overflow

在我的C#服务器-客户端程序中,我有以下问题:

使用客户机之一登录到服务器后,

在与IP连接并键入“ LOGIN xxxxxxx”后,服务器自动通过StackOverFlowException关闭。

client server

客户代码

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace SIKTcpClient
{
    class Program
    {
        private const int Port = 3000;
        private static Socket _socket;
        private const int attemptsLimit = 2;
        private const int BufferSize = 2048;
        private static byte[] buffer = new Byte[BufferSize];
        private static string _login;
        static void Main(string[] args)
        {

            Console.WriteLine("Write ip adress");
            var input = Console.ReadLine();
            var ipAdress = input.Length < 2 ? GetIpAdress() : input;
            if (input.Length < 2)
                Console.WriteLine(ipAdress);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Connect(ipAdress);
            Console.WriteLine("Your login");
            try
            {
                if (input.Length < 2)
                {
                    Console.WriteLine(_login);
                    _socket.Send(Encoding.ASCII.GetBytes(_login));
                }
                while (true)
                {
                    var result = Console.ReadLine();
                    var bytes = Encoding.ASCII.GetBytes(result);
                    _socket.Send(bytes);
                }
            }
            catch (SocketException)
            {
                Console.WriteLine("Server was shut down.");
            }
            catch(Exception ex)
            {
                Console.WriteLine($"Exception: {ex.Message}");
            }
        }

        static void Connect(string ipAdress)
        {
            var attempts = 0;
            while (!_socket.Connected && attempts < attemptsLimit)
            {
                try
                {
                    ++attempts;
                    var result = _socket.BeginConnect(ipAdress, Port, EndConnect, null);
                    result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3));
                    Thread.Sleep(3000);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception: {ex.Message}");
                }
            }
            if(!_socket.Connected)
            {
                Console.WriteLine("Could not connect to server");
                return;
            }
        }

        private static void EndConnect(IAsyncResult asyncResult)
        {
            try
            {
                _socket.EndConnect(asyncResult);
                if (_socket.Connected)
                {
                    _socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _socket);
                }
                else
                {
                    Console.WriteLine("End of connection attempt, fail to connect...");
                }
            }
            catch (SocketException)
            {
                Console.WriteLine("Waiting for server...");
            }
            catch(Exception ex)
            {
                Console.WriteLine("Cant connnect to server... " + ex.Message);
            }
        }

        private static void ReceiveCallback(IAsyncResult asyncResult)
        {
            try
            {
                var socket = (Socket)asyncResult.AsyncState;
                if (socket.Connected)
                {
                    var received = socket.EndReceive(asyncResult);
                    if (received > 0)
                    {
                        var data = new byte[received];
                        Buffer.BlockCopy(buffer, 0, data, 0, data.Length);
                        var message = Encoding.UTF8.GetString(data);
                        if (!string.IsNullOrWhiteSpace(message))
                            Console.Write("Server: " + Encoding.UTF8.GetString(data));
                        socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
                    }
                }
            }
            catch(SocketException)
            {
                Console.WriteLine("Server was shut down.");
            }
            catch(Exception ex)
            {
                Console.WriteLine("Receive callback failed "+ ex.Message);
            }
        }

        private static string GetIpAdress()
        {
            var random = new Random();
            var r = random.Next(100000000);
            _login = "LOGIN " + r;
            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
            {
                socket.Connect("8.8.8.8", 65530);
                var endPoint = socket.LocalEndPoint as IPEndPoint;
                var localIP = endPoint.Address.ToString();
                return localIP;
            }
        }
    }
}

服务器代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SIKTcpServer.Constants;
using SIKTcpServer.Models;
using SIKTcpServer.Models.Cards;

namespace SIKTcpServer
{
    class Program
    {
        private static Socket _socket;
        private const int Port = 3000;
        private const int BufferSize = 2048;
        private static byte[] _buffer = new byte[BufferSize];
        private static List<Player> _players = new List<Player>();
        private static bool _gameStarted = false;
        private static List<Player> _playersInRound;
        private static readonly int[] _ids = new int[5] { 1, 2, 3, 4, 5 };
        private static List<AbstractCard> _turnCards;

        static void Main(string[] args)
        {
            Console.Title = "Server";
            GatherPlayers();
            Console.ReadKey();


        }

        private static void GatherPlayers()
        {
            //var a = LoadCards();

            Console.WriteLine("Waiting for players...");
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.Bind(new IPEndPoint(IPAddress.Any, Port));
            _socket.Listen(0);
            _socket.BeginAccept(new AsyncCallback(AcceptCallback), null);
            while(_players.Count < 2) { }
            Console.WriteLine("asd");

        }

        private static void AcceptCallback(IAsyncResult asyncResult)
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socket = _socket.EndAccept(asyncResult);
                if (_players.Count > 2 || _gameStarted)
                {
                    socket.Send(GetAsciiBytes("Sorry we have 5 players already"));
                    return;
                }
                socket.Send(GetAsciiBytes("CONNECT"));
                Console.WriteLine("Connected new socket");
                socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
                _socket.BeginAccept(new AsyncCallback(AcceptCallback), socket);
            }
            catch
            {
                RemovePlayer(socket);
                socket.Dispose();
            }
        }

        private static void ReceiveCallback(IAsyncResult asyncResult)
        {
            Socket current = (Socket)asyncResult.AsyncState;
            int received;

            try
            {
                received = current.EndReceive(asyncResult);
            }
            catch (SocketException)
            {
                Console.WriteLine("Client forcefully disconnected");
                current.Close();
                RemovePlayer(current);
                return;
            }

            byte[] recBuffer = new byte[received];
            Array.Copy(_buffer, recBuffer, received);
            string text = Encoding.ASCII.GetString(recBuffer);
            Console.WriteLine("Received Text: " + text);

            if (_players.Count > 4)
            {
                current.Send(GetAsciiBytes("Sorry we have 5 players already"));
                current.Close();
                current.Dispose();
            }
            else if (text.Length < 7 || text.Substring(0, 5) != "LOGIN" || string.IsNullOrWhiteSpace(text.Substring(6, 2)))
            {
                Console.WriteLine("Text is an invalid request");
                var data = Encoding.ASCII.GetBytes("Invalid request");
                current.Send(data);
                Console.WriteLine("Warning Sent");
                current.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, current);
            }
            else
            {
                current.Send(GetAsciiBytes("OK"));
                _players.Add(new Player(current));
                Console.WriteLine("Player OK");
            }
        }

        private static void Round()
        {
            StartRound();
            while (_playersInRound.Count > 1 && _turnCards.Count > 0)
            {
                foreach (var player in _playersInRound)
                {
                    if (player.IsEliminated)
                    {

                    }
                    if (player.SkipTurn)
                    {
                        player.SkipTurn = false;
                        continue;
                    }

                    var card = GetRandomCard();
                    player.Cards.Add(card);
                    player.Socket.Send(GetAsciiBytes($"YOUR MOVE {card.Name}"));
                    var playerCardsNames = player.Cards.Select(x => x.Name).ToArray();
                    if (player.HaveCountessAndKingOrPrince)
                    { 
                        while(true)
                        {
                            player.Socket.Receive(_buffer, 0, _buffer.Length, SocketFlags.None);
                        }
                    }
                    var splittedMessage = GetStringFromBytes(_buffer).Split(new char[0]);
                    var choosenPlayer = Int32.Parse(splittedMessage[2] ?? "0");
                    var choosenSecondCard = splittedMessage[3] ?? "";
                    var playedCard = player.Cards.Where(x => x.Name.ToString() == splittedMessage[1]).First();
                    player.Cards.Where(x => x.Name == playedCard.Name).FirstOrDefault().Action(player, _playersInRound.Where(x => x.Id == choosenPlayer).FirstOrDefault(), choosenSecondCard);
                    //Array.Clear(_buffer, 0, _buffer.Length);
                    RemoveEliminatedPlayers();
                }
            }
        }
        private static void StartRound()
        {
            MixPlayers();
            LoadCards();
            GiveStartingCardsToPlayers();
            foreach (var player in _playersInRound)
            {
                player.Socket.Send(GetAsciiBytes($"START {player.Id.ToString()} {player.Cards[0]}"));
            }
        }

        private static void MixPlayers()
        {
            var ids = _ids.ToList();
            var random = new Random();
            for (var i = 0; i < 5; i++)
            {
                var randomListIndex = random.Next(ids.Count);
                _playersInRound[i].Id = ids[randomListIndex];
                ids.RemoveAt(randomListIndex);
            }
            _playersInRound.OrderBy(x => x.Id);
        }

        private static void RemovePlayer(Socket socket)
        {
            _players.Remove(_players.Where(x => x.Socket == socket).FirstOrDefault());
        }

        private static List<AbstractCard> LoadCards()
        {
            var allCards = new List<AbstractCard>();
            var values = Enum.GetValues(typeof(CardName)).Cast<CardName>().ToArray();
            foreach (var value in values)
            {
                for (var i = 0; i < (int)Enum.Parse(typeof(CardAmount), value.ToString()); i++)
                {
                    switch (value)
                    {
                        case CardName.Baron:
                            allCards.Add(new BaronCard());
                            break;
                        case CardName.Countess:
                            allCards.Add(new CountessCard());
                            break;
                        case CardName.Guard:
                            allCards.Add(new GuardCard());
                            break;
                        case CardName.Handmaiden:
                            allCards.Add(new HandmaidenCard());
                            break;
                        case CardName.King:
                            allCards.Add(new KingCard());
                            break;
                        case CardName.Priest:
                            allCards.Add(new PriestCard());
                            break;
                        case CardName.Prince:
                            allCards.Add(new PrinceCard());
                            break;
                        case CardName.Princess:
                            allCards.Add(new PrincessCard());
                            break;
                    }
                }
            }
            return allCards;
        }

        private static AbstractCard GetRandomCard()
        {
            var random = new Random();
            var randomIndex = random.Next(_turnCards.Count);
            var randomCard = _turnCards[randomIndex];
            _turnCards.RemoveAt(randomIndex);
            return randomCard;
        }

        private static void GiveStartingCardsToPlayers()
        {
            foreach (var player in _playersInRound)
            {
                player.Cards.Add(GetRandomCard());
            }
        }

        private static void RemoveEliminatedPlayers()
        {
            Predicate<Player> eliminated = (Player player) => { return player.IsEliminated == true; };
            _playersInRound.RemoveAll(eliminated);
            _players.ForEach(x => x.ClearElimination());
        }

        private static byte[] GetAsciiBytes(string text)
        {
            return Encoding.ASCII.GetBytes(text);
        }

        private static string GetStringFromBytes(byte[] bytes)
        {
            return Encoding.ASCII.GetString(bytes);
        }
    }
}

一个糟糕的stackoverflow网站说,我的帖子似乎主要是代码,但是我已经描述了上面的所有内容,因此在这里对此毫无意义的文字表示抱歉。

1 个答案:

答案 0 :(得分:0)

您已经创建了一个静态缓冲区数组,该数组向您发出stackoverflow异常,这是因为多个客户端同时请求。他们都使用了这个静态缓冲区。在开发中创建静态缓冲区不是一个好方法。 您必须提出这样的一些新登录信息。

 public class SocketPacketforROD
{
    public System.Net.Sockets.Socket CurrentSocket;

    //test
    public int last_buffer_read = 0;
    public int last_socket_payload_size = 0;

    public byte[] Data = null; // new byte[Server.bufferLength];

    public SocketPacketforROD_State m_state = SocketPacketforROD_State.socket_state_payload_size;

    public void allocate(int bytes)
    {
        // socket_buffer_length = bytes;
        Data = new byte[bytes];
    }
}

在您的onreceiveddata方法中使用了此套接字对象类

 string Data = Encoding.ASCII.GetString(socketData.Data);
                        Logger.WriteLog("Message Received length : " + Data.Length + " from: " + socketData.CurrentSocket.RemoteEndPoint, LogLevel.GENERALLOG);

                        socketData.m_state = SocketPacketforROD_State.socket_state_payload_size;

设置接收回叫

  private void SetupReceiveCallback(Socket objClientSocket)
    {
        try
        {
            AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
            SocketPacketforROD theSocPkt = new SocketPacketforROD();
            theSocPkt.last_socket_payload_size = 4;
            theSocPkt.allocate(4);
            theSocPkt.CurrentSocket = objClientSocket;
            Logger.WriteLog("After New Socket buffer Length : " + theSocPkt.Data.Length, LogLevel.GENERALLOG);
            objClientSocket.BeginReceive(theSocPkt.Data, 0, theSocPkt.Data.Length, SocketFlags.None, recieveData, theSocPkt);
        }
        catch (OutOfMemoryException MemEXP)
        {
            Logger.WriteException(MemEXP);
        }
        catch (Exception E)
        {
            Logger.WriteException(E);
        }
    }