使用 BinaryReader/Writer 的 C# Socket 从读取器获取错误数据
Posted
技术标签:
【中文标题】使用 BinaryReader/Writer 的 C# Socket 从读取器获取错误数据【英文标题】:C# Socket using BinaryReader/Writer is getting the wrong data from reader 【发布时间】:2019-03-06 04:41:21 【问题描述】:我正在做一个班级项目,我必须创建一个套接字服务器,然后是一堆从队列中请求票证的假客户端。我的一切工作都很好,但是,当我从 Socket 流中读取我的 Ticket 对象时,我只收到了第一个发送的对象。
在Console.WriteLine($"ID paramData.ClientID got ticket tick.TicketID for show tick.EventName");
行,我得到了在 for 循环期间生成的唯一客户端 ID,但是,我每次都得到 0 的票证 ID。
我有一些想法,但我不确定为什么会这样。首先,通过套接字发送第一张票,然后每次都重新使用该票,但我不确定为什么会发生这种情况,因为我在发送之前将其出列。
另一个想法是我只是在做线程完全错误,但我不明白同一张票是如何出现在不同线程上的。
这是执行代码的屏幕截图,其中包含 10 次购买尝试和 5 个可用门票
完整代码:
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】:我相信,这不是 “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;
【讨论】:
哇,我今天讨厌互联网。我坐在这里强调如何正确完成这项任务,而像我的数据序列化这样简单的事情才是真正的问题..以上是关于使用 BinaryReader/Writer 的 C# Socket 从读取器获取错误数据的主要内容,如果未能解决你的问题,请参考以下文章