2013-05-30 68 views
1

我正在使用C#套接字。我正在做一個拍賣服務器和客戶端項目。控制檯模式。 其實我有1個服務器運行異步多個客戶端。客戶 - 服務器拍賣系統。控制檯模式

主要問題:1次拍賣結束時,服務器必須發送消息給勝者(如果存在),賣家和寬鬆者。我需要一種時鐘來觸發事件。

在客戶端上我能發送這樣的命令:

  • 「註冊的用戶名密碼」
  • 「登錄用戶名密碼」
  • 「信用XXX.XX」
  • 「創建產品MIN_PRICE時間「 - creat 1 auction
  • etc ..

現在我遇到了拍賣系統的邏輯問題。

當服務器讀取(command ==「creat」)時,它必須創建具有相應信息的拍賣。 這怎麼辦?每次拍賣1線程?

當時間結束的服務器必須repply到:

  • 贏家(產品名,獲獎者的出價)
  • loosers(產品名,他的最後報價,贏家投標)
  • 創造者(如果他的產品售出)

我想:

  1. 服務器讀取命令「創造」
  2. 服務器科瑞對於拍賣一個新的線程
  3. 線程有一個計時器,看到(thread.timer == time_to_end)?
  4. 當(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://goo.gl/wQZdb

+0

我認爲,我是需要解決的解釋在這裏:http://www.codeproject.com/Articles/461682/Client-Server-Event-Subscription-Techniques-in-Csh但我不知道如何實現其中一個事件訂閱技術與我的訂單線程序。所以我選擇創建通知命令,買家和賣家可以看到他的拍賣的狀態。 – user2437205

回答

0

定時器不必在單個線程。實際上,拍賣數據並不在單獨的線程中。您可以創建數據結構 - 拍賣(類拍賣,所有者,參與者,出價)並將其存儲在主線程中。您需要的是一個專用線程,可持續檢查拍賣數據結構(您可以將其存儲在數據庫或內存中,無論您的需要如何),以獲取已過去的所有拍賣並將通知發送給所有拍賣參與者(所有者和參與者)。

+0

你的建議聽起來不錯。 但是,由於我在多線程方面並不是很有經驗: 是否有可能在沒有活動拍賣的情況下讓線程處於睡眠狀態,並在持續拍賣時將其喚醒? – user2437205

+0

必須有(監控)線程來檢查是否有正在進行的拍賣。所以不,必須有一個線程來檢查是否有正在進行的選項。關於你在多線程方面缺乏經驗,這對你來說是一個很好的練習,也是獲得經驗的機會。確保閱讀多線程/鎖定的資源。閱讀Observer/Publisher-Subscriber設計模式以及我認爲您可以將這些模式用於您的設計。 – rro

相關問題