Сетевое программирование в .NET. Расшифровка IP-адреса (IP address specification). Обеспечение надежности доставки пакетов, страница 35

OnCommandRecieved is called when a remote host sends a command to Genesis. The eventargs for this event allows access to the ICommand object interface (via the SentCommand property) that contains the information relating to the command sent, and allows access to the data fields and opcode. There is also the ability to get the object corresponding to the remote host that sent the command (via the Sender property). This event is only fired from authorized hosts. The chat server uses this event to handle incoming chat messages and user list requests.

OnConnectionStateChanged is fired when a remote host connects or disconnects from the Genesis instance. The eventargs contain information regarding the host, whether it connected or disconnected, and a disconnection reason if the latter. The chat server uses this event to send a connected user list to the newly connected clients.

Creating A Client

Let's look now at the client side of the chat project, "GenesisChatClient". This is similar to the server application in that it instantiates an instance of Genesis and hooks up various events, however some new events are hooked:

m_UDP.OnListenStateChanged += new ListenHandler(m_UDP_OnListenStateChanged);

m_UDP.OnLoginRequested += new SendLoginHandler(m_UDP_OnLoginRequested);

m_UDP.OnAuthFeedback += new AuthenticatedHandler(m_UDP_OnAuthFeedback);

m_UDP.OnConnectionStateChanged += new

ConnectionStateChangeHandler(m_UDP_OnConnectionStateChanged);

m_UDP.OnCommandReceived += new IncomingCommandHandler(m_UDP_OnCommandReceived);

m_UDP.OnConnectionAuth += new ConnectionAuthHandler(m_UDP_OnConnectionAuth);

m_UDP.OnSocketError += new SocketErrorHandler(m_UDP_OnSocketError);

m_UDP.OnConnectionRequestTimedOut += new

RequestTimedOutHandler(m_UDP_OnConnectionRequestTimedOut);

OnLoginRequested is triggered when the server requests the login details from the client. The client must send a command packet back to the server with the opcode OPCODE_LOGINDETAILS and the appropriate data fields. In the chat sample, this packet contains the user's nickname and the server password:

void OnLoginRequested(object o, LoginSendEventArgs e)

{

if(e.Connected)

{

e.ServerConnection.SendUnreliableCommand(0,

GenesisConsts.OPCODE_LOGINDETAILS,

new string[] {txtServerPW.Text, txtNickName.Text} );

spState.Text = "Sending login details...";

}

else

{

spState.Text = "Connection rejected - " + e.Reason;

}

}

The Connected property of the LoginSendEventArgs object is false if the server is unable to accept the connection, for example, if it has reached the maximum capacity. The reason for the rejection is also accessible if needed, in the Reason property.

OnAuthFeedback is triggered when the server has made a decision on whether or not to accept the connection. The eventargs contains a value that determines whether the auth succeeded, and the reason for the failure if otherwise.

OnConnectionAuth is fired when a remote host tries to connect to Genesis, remember this is used in the chat server for authenticating remote hosts. The chat client can accept no connections (as it is acting as a client), so a small piece of code is entered here to reject the connection and send a rejection reason back. If the event was not hooked at all by the client application, the connection would still be rejected, but no reason would be sent to the host attempting to connect.

void m_UDP_OnConnectionAuth(object o, ConnectionAuthEventArgs e)

{

//Clients don't accept connections.

e.AllowConnection = false;

e.DisallowReason = "Can't connect directly to a chat client";

}

One thing of importance is how connections are established from the client. It starts in the chat client with the following code:

void btnConnect_Click(object sender, System.EventArgs e)

{

server_ip = txtServerIP.Text;

m_UDP.RequestConnect(ref server_ip,

Convert.ToInt32(txtServerPort.Text),

out server_req_id);

spState.Text = "Connecting...";

btnConnect.Enabled = true;

}