客户端 - 服务器拍卖系统。控制台模式

时间:2013-05-30 16:58:45

标签: c# multithreading sockets tcp client-server

我正在使用C#套接字。我正在做一个拍卖服务器和客户端项目。控制台模式。 实际上我有一台服务器异步运行多个客户端。

主要问题:当1次拍卖结束时,服务器必须向获胜者(如果存在),卖家和放松者发送消息。我需要一种时钟来触发事件。

在客户端,我可以发送如下命令:

  • “注册用户名密码”
  • “登录用户名密码”
  • “credit xxx.xx”
  • “创建产品min_price持续时间” - 创建1拍卖
  • 等。

现在我对拍卖系统的逻辑感到麻烦。

当服务器读取(命令==“creat”)时,它必须使用相应的信息创建拍卖。 如何才能做到这一点?每次拍卖都有1个帖子?

当服务器的时间结束时必须接通:

  • 获胜者(产品名称,中标者)
  • 松散(产品名称,他的最后一次出价,中标)
  • 创作者(如果他的产品被出售)

我想:

  1. 服务器读取命令“creat”
  2. 服务器为该拍卖创建新主题
  3. 线程有一个看到的计时器(thread.timer == time_to_end)?
  4. 当(thread.timer = time_to_end)发送所有消息时!
  5. 这个伪代码是否可以执行?

    我必须使用哪些课程?

    服务器代码:

    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

1 个答案:

答案 0 :(得分:0)

计时器不必是单独的线程。实际上,拍卖数据不是单独的线程。您可以为此创建数据结构 - 拍卖(类拍卖,所有者,参与者,出价)并将其存储在主线程中。您需要的是一个专用线程,它不断检查Auctions数据结构(您可以将其存储在数据库或内存中,满足您的需求)以获得已经过去的所有拍卖并向所有拍卖参与者发送通知(所有者和参与者) )。