我正在使用 C# 套接字。我正在做一个拍卖服务器和客户端项目。控制台模式。实际上,我有 1 台服务器为多个客户端异步运行。
主要问题:当 1 次拍卖结束时,服务器必须向获胜者(如果存在)、卖方和松手发送消息。我需要一种时钟来触发事件。
在客户端上,我可以发送如下命令:
- “注册用户名密码”
- “登录用户名密码”
- “信用 xxx.xx”
- "create product min_price duration" -- 创建 1 次拍卖
- ETC..
现在我遇到了拍卖系统的逻辑问题。
当服务器读取 (command == "creat") 时,它必须使用相应的信息创建拍卖。如何才能做到这一点?每次拍卖 1 个线程?
当时间结束时,服务器必须回复:
- 获胜者(产品名称,获胜者出价)
- 宽松者(产品名称,他的最后出价,获胜者出价)
- 创建者(如果他的产品已售出)
我想过:
- 服务器读取命令“创建”
- 服务器为该拍卖创建一个新线程
- 线程有一个计时器可以看到(thread.timer == time_to_end)?
- 当 (thread.timer = time_to_end) 发送所有消息时!
这个伪代码可以执行吗?
我必须使用哪些类?
服务器代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using Server;
using System.IO;
namespace Server
{
class Program
{
private static TcpClient _cashierClient = new TcpClient();
private static Dictionary<string, User> loggedUsers = new Dictionary<string, User>(); // <username, User>
private static Dictionary<string, int> loggedUsers2 = new Dictionary<string, int>(); // <IPEndPoint, ID>
private static List<User> registeredUsers = new List<User>();
private static byte[] _buffer = new byte[1024];
private static List<Socket> _clientSockets = new List<Socket>();
private static Socket _serverSocket = new Socket
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
static void Main(string[] args)
{
Console.Title = "Server";
ConnectToCashier();
SetupServer();
Console.ReadLine();
}
private static void ConnectToCashier()
{
Console.WriteLine("Connecting to Cashier...");
_cashierClient.Connect(IPAddress.Loopback, 101);
Stream stream = _cashierClient.GetStream();
byte[] receivedBuf = new byte[1024];
int rec = stream.Read(receivedBuf, 0, 1024);
byte[] data = new byte[rec];
Array.Copy(receivedBuf, data, rec);
Console.WriteLine(Encoding.ASCII.GetString(data));
}
private static void SetupServer()
{
Console.WriteLine("Setting up server...");
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 100)); //Bind any interfaces on port 100
_serverSocket.Listen(5); // Max 5 em Lista de espera
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private static void AcceptCallback(IAsyncResult AR)
{
Socket socket = _serverSocket.EndAccept(AR);
_clientSockets.Add(socket);
Console.WriteLine("Client " + socket.RemoteEndPoint.ToString() + " connected");
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private static void ReceiveCallBack(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
int received = socket.EndReceive(AR);
byte[] dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
string text = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine(socket.RemoteEndPoint.ToString() + " sent: " + text);
string response = string.Empty;
string command = text.ToLower().Split()[0]; // "command word1 word2 word... wordX wordX+1"
int words = text.Split().Count(); // count the number of words + command
if (command == "get_time" && words == 1) // SERVER TIME
{
response = DateTime.Now.ToLongTimeString();
}
else if (command == "register" && words == 3) // REGIST USER
{
string[] split = text.Split();
if (userExists(split[1]))
{
response = "'" + split[1] + "' already in use. Choose another username";
}
else
{
newUser(split[1], split[2]); //split[1] = name, split[2] = password
response = "'" + split[1] + "' Successfully Registered";
}
}
else if (command == "login" && words == 3) // LOG IN
{
string[] split = text.Split();
if (!userExists(split[1]))// check for username
{
response = "Invalid Username";
}
else if (!userExists(split[1], split[2])) // check for username and corresponding password
{
response = "Wrong Password";
}
else if (loggedUsers.ContainsKey(split[1]) ||
loggedUsers2.ContainsKey(socket.RemoteEndPoint.ToString())) //checks if user is on hashtree by the [KEY = username] or [KEY = IPAdress]
{
int id;
if (loggedUsers2.TryGetValue(socket.RemoteEndPoint.ToString(), out id)) // O cliente já está logado com alguma conta
{
User user = getUser(id);
response = "You're allready Logged In As '" + user.username + "'";
}
else
{ // O cliente não está logged in e está a tentar entrar numa contra logada noutro computador
response = "Another Computer is currently logged onto this account";
}
}
else
{
Console.WriteLine(socket.RemoteEndPoint.ToString() + " loged in");
response = "Successfully Logging In";
//User user = new User(split[1], split[2]);
User user = getUser(split[1], split[2]); //split[1] = name, split[2] = password
loggedUsers.Add(user.username, user);
loggedUsers2.Add(socket.RemoteEndPoint.ToString(), user.ID);
}
}
else if (command == "balance" && words == 1) // SHOW AVAILABLE CASH
{
if (loggedUsers2.ContainsKey(socket.RemoteEndPoint.ToString())) // Verifica se está logado
{
int userID = loggedUsers2[socket.RemoteEndPoint.ToString()];
byte[] dataToSend = Encoding.ASCII.GetBytes("balance " + userID);
Stream stream = _cashierClient.GetStream();
stream.Write(dataToSend, 0, dataToSend.Length);
byte[] dataBuffer = new byte[1024];
int rec = stream.Read(dataBuffer, 0, 1024);
byte[] dataReceived = new byte[rec];
Array.Copy(dataBuffer, dataReceived, rec);
response = Encoding.ASCII.GetString(dataReceived);
}
else // Se não estiver logado...
{
response = "You are not logged in";
}
}
else if (command == "deposit" && words == 2)
{
if (loggedUsers2.ContainsKey(socket.RemoteEndPoint.ToString())) // Verifica se está logado
{
string[] split = text.Split();
split[1] = split[1].Replace(".", ","); // Se o user escrever ####.## altera para ####,##
decimal value;
if (Decimal.TryParse(split[1], out value)) // It's a decimal
{
if (value < 10) // Abaixo da quantia minima
{
response = "Minimum Deposit 10 EUROS";
}
else // Quantia aceitavel
{
int userID = loggedUsers2[socket.RemoteEndPoint.ToString()];
byte[] dataToSend = Encoding.ASCII.GetBytes("deposit " + userID + " " + value);
Stream stream = _cashierClient.GetStream();
stream.Write(dataToSend, 0, dataToSend.Length);
byte[] dataBuffer = new byte[1024];
int rec = stream.Read(dataBuffer, 0, 1024);
byte[] dataReceived = new byte[rec];
Array.Copy(dataBuffer, dataReceived, rec);
response = Encoding.ASCII.GetString(dataReceived);
}
}
else // No it's not.
{
response = "Invalid Cash Format. Use 'deposit ####,##'";
}
}
else // Se não estiver logado...
{
response = "You are not logged in";
}
}
else // Comando inválido
{
response = "Invalid Request";
}
byte[] data = Encoding.ASCII.GetBytes(response);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallBack), socket);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
}
private static User getUser(string username, string password)
{
foreach (User user in registeredUsers)
{
if (user.username == username && user.password == password)
return user;
}
return null;
}
private static User getUser(int id)
{
foreach (User user in registeredUsers)
{
if (user.ID == id)
return user;
}
return null;
}
private static bool userExists(string username, string password)
{
foreach (User user in registeredUsers)
{
if (user.username == username && user.password == password)
return true;
}
return false;
}
private static bool userExists(string username)
{
foreach (User user in registeredUsers)
{
if (user.username == username)
return true;
}
return false;
}
private static void newUser(string username, string password)
{
User user = new User(username, password);
registeredUsers.Add(user); // adiciona à lista de user's registados
int userID = user.ID;
byte[] dataToSend = Encoding.ASCII.GetBytes("register " + userID);
Stream stream = _cashierClient.GetStream();
stream.Write(dataToSend, 0, dataToSend.Length);
}
private static void SendCallBack(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
}
}
}
客户代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace Client
{
class Program
{
private static Socket _clientSocket = new Socket
(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
static void Main(string[] args)
{
Console.Title = "Client";
LoopConnect();
SendLoop();
Console.ReadLine();
}
private static void SendLoop()
{
while (true)
{
Console.WriteLine("Enter a request: ");
string req = Console.ReadLine();
byte[] buffer = Encoding.ASCII.GetBytes(req);
_clientSocket.Send(buffer);
byte[] receivedBuf = new byte[1024];
int rec = _clientSocket.Receive(receivedBuf);
byte[] data = new byte[rec];
Array.Copy(receivedBuf, data, rec);
Console.WriteLine("Received: " + Encoding.ASCII.GetString(data));
}
}
private static void LoopConnect()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
_clientSocket.Connect(IPAddress.Loopback, 100);
}
catch (SocketException) {
Console.Clear();
Console.WriteLine("Connection attempts: " + attempts.ToString());
}
}
Console.Clear();
Console.WriteLine("Connected");
}
}
}
在此打印上,您可以看到正在运行的服务器和客户端。收银员服务器对于这个问题并不重要。