Сокет C # с использованием BinaryReader / Writer получает неверные данные от читателя - PullRequest
0 голосов
/ 01 октября 2018

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

В строке Console.WriteLine($"ID {paramData.ClientID} got ticket {tick.TicketID} for show {tick.EventName}"); я получаю свой уникальный идентификатор клиента, который генерируется во время цикла for, однако каждый раз получаю идентификатор билета, равный 0.

У меня есть несколько мыслей, но я просто не уверен, почему это происходит.Во-первых, отправляет первый билет через сокет, а затем повторно использует этот билет каждый раз, но я не уверен, почему это произойдет, потому что я удаляю один из них перед отправкой.

Еще одна мысль - я просто неправильно выполняю потоки, но не понимаю, как один и тот же тикет отображается в разных потоках.

Вот скриншот выполненного кода с 10попыток покупки и 5 доступных билетов enter image description here

Весь код:

class Program
{
    static ConcurrentQueue<Ticket> _TicketStorage = new ConcurrentQueue<Ticket>();
    static Socket ServerSocket;

    static void Main(string[] args)
    {
        Console.WriteLine("Starting Server ...");

        // Gets the event name to apply to all the tickets
        Console.Write("Enter Name of Event: ");
        var eventName = Console.ReadLine();

        // Allows the user to set the ticket count or defaults to 500
        Console.Write("\nEnter Max Number of Tickets (Default: 500): ");
        var ticketCountTry = int.TryParse(Console.ReadLine(), out int TicketCountResult);

        // Setups up the ticket q
        Console.WriteLine("Initilizing Ticket Storage");
        for (int i = 0; i < (ticketCountTry ? TicketCountResult : 5); i++)
        {
            _TicketStorage.Enqueue(new Ticket(eventName, i));
        }

        Console.Clear();

        // Finish line for application
        Console.WriteLine("Server is ready to process requests");

        var ServerThread = Task.Factory.StartNew(()=> 
        {
            StartServerListener();
        },TaskCreationOptions.LongRunning);

        StartFakeClients();

        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }

    static void StartFakeClients()
    {
        Console.Write("Enter number of tickets to attempt to purchase (Default: 600): ");
        var attemptNumberTry = int.TryParse(Console.ReadLine(), out int attemptAmount);

        // Setup all the connections to be in the ready state
        for (int i = 0; i < (attemptNumberTry ? attemptAmount : 10); i++)
        {
            ThreadPool.QueueUserWorkItem(FakeClientWorker, new
            {
                ClientID = i
            });

            Thread.Sleep(TimeSpan.FromSeconds(2));
        }
    }

    static void FakeClientWorker(object state)
    {
        dynamic paramData = state;

        // Create a connection to the server
        var Connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        Connection.Connect(IPAddress.Loopback, 11000);


        using (var bReader = new BinaryReader(new NetworkStream(Connection, true), Encoding.UTF8, false))
        {
            // Create my high level reader to parse incoming data
            var dataBlock = bReader.ReadString();

            if (!string.IsNullOrEmpty(dataBlock))
            {
                Ticket tick = JsonConvert.DeserializeObject<Ticket>(dataBlock);
                Console.WriteLine($"ID {paramData.ClientID} got ticket {tick.TicketID} for show {tick.EventName}");
            }
            else
            {
                // Didn't get a ticket
                Console.WriteLine($"ID {paramData.ClientID} didn't get a ticket");
            }
        }
    }

    static void StartServerListener()
    {
        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 11000);

        ServerSocket = new Socket(AddressFamily.InterNetwork,
        SocketType.Stream, ProtocolType.Tcp);
        ServerSocket.Bind(localEndPoint);
        ServerSocket.Listen(100);

        while (true)
        {
            var clientSocket = ServerSocket.Accept();

            // You just got a new client asking for a ticket
            // Send this connection to another thread and then continue listening for connections
            ThreadPool.QueueUserWorkItem(DoServerWork, clientSocket);
        }
    }

    static void DoServerWork(object clientSocket)
    {
        // Get the next ticket from the q
        var hasNewTickets = _TicketStorage.TryDequeue(out Ticket EventTicket);

        // Start a writer
        var n = new NetworkStream((Socket)clientSocket, false);
        using (var bWriter = new BinaryWriter(new NetworkStream((Socket)clientSocket, true), Encoding.UTF8, false))
        {
            // I have my writer now I need to send this data
            bWriter.Write((hasNewTickets ? JsonConvert.SerializeObject(EventTicket) : String.Empty));
        } // Dispose of the advanced network stream, Dispose of the binary writer, close the connection
    }
}

/// <summary>
/// A structure for storing information about an event
/// </summary>
public class Ticket
{
    /// <summary>
    /// Unique identifer for the ticket 
    /// </summary>
    public readonly int TicketID;

    /// <summary>
    /// Event name this ticket represents
    /// </summary>
    public readonly String EventName;

    public Ticket(String EventName, int ID)
    {
        this.EventName = EventName;
        TicketID = ID;
    }
}

1 Ответ

0 голосов
/ 01 октября 2018

Полагаю, это не "Проблема BinaryReader / Writer" .Вы используете JsonConvert (из Json.Net , я думаю) для сериализации и десериализации вашего объекта.Я думаю, что если вы отлаживаете свой проект, вы можете обнаружить, что dataBlock, переданный методу JsonConvert.DeserializeObject<Ticket>(), просто в порядке.

Истинная причина в том, что ваш класс Ticket не имеет конструктора по умолчанию.В этом случае JsonConvert попытается сопоставить имена параметров конструктора со значениями из JSON.Вот почему вы получаете правильный EventName, но по умолчанию TicketID (0).Попробуйте изменить ваш конструктор на это:

public Ticket(String EventName, int TicketID)
{
    this.EventName = EventName;
    this.TicketID = TicketID;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...