我正在使用C#套接字。我正在做一個拍賣服務器和客戶端項目。控制檯模式。 其實我有1個服務器運行異步多個客戶端。客戶 - 服務器拍賣系統。控制檯模式
主要問題:1次拍賣結束時,服務器必須發送消息給勝者(如果存在),賣家和寬鬆者。我需要一種時鐘來觸發事件。
在客戶端上我能發送這樣的命令:
- 「註冊的用戶名密碼」
- 「登錄用戶名密碼」
- 「信用XXX.XX」
- 「創建產品MIN_PRICE時間「 - creat 1 auction
- etc ..
現在我遇到了拍賣系統的邏輯問題。
當服務器讀取(command ==「creat」)時,它必須創建具有相應信息的拍賣。 這怎麼辦?每次拍賣1線程?
當時間結束的服務器必須repply到:
- 贏家(產品名,獲獎者的出價)
- loosers(產品名,他的最後報價,贏家投標)
- 創造者(如果他的產品售出)
我想:
- 服務器讀取命令「創造」
- 服務器科瑞對於拍賣一個新的線程
- 線程有一個計時器,看到(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");
}
}
}
在此打印,你可以看到服務器的運行狀態和客戶端。收銀臺服務器對於這個問題並不重要。
我認爲,我是需要解決的解釋在這裏:http://www.codeproject.com/Articles/461682/Client-Server-Event-Subscription-Techniques-in-Csh但我不知道如何實現其中一個事件訂閱技術與我的訂單線程序。所以我選擇創建通知命令,買家和賣家可以看到他的拍賣的狀態。 – user2437205