2

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

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

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

  • “注册用户名密码”
  • “登录用户名密码”
  • “信用 xxx.xx”
  • "create product min_price duration" -- 创建 1 次拍卖
  • ETC..

现在我遇到了拍卖系统的逻辑问题。

当服务器读取 (command == "creat") 时,它必须使用相应的信息创建拍卖。如何才能做到这一点?每次拍卖 1 个线程?

当时间结束时,服务器必须回复:

  • 获胜者(产品名称,获胜者出价)
  • 宽松者(产品名称,他的最后出价,获胜者出价)
  • 创建者(如果他的产品已售出)

我想过:

  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

4

1 回答 1

0

计时器不必在单独的线程中。实际上,拍卖数据并不在单独的线程中。您可以为此创建一个数据结构-Auctions(类 Auction、Owner、Participant、Bids)并将其存储在主线程中。您需要一个专用线程来持续检查拍卖数据结构(您可以将其存储在数据库或内存中,无论您的需要如何)以获取所有已过去的拍卖并向所有拍卖参与者(所有者和参与者)发送通知)。

于 2013-05-31T06:49:39.063 回答