}

Figure 11-4 shows how the server and client look like when you run both applications.

Figure 11-4 

Building a Multi-User Server Application

The client-server applications built in the previous section can accept only a single client. A client connects and sends some data to the server; the server receives it, sends the data back to the client, and then exits. While this is a simple demonstration of a client-server application, it isn't a very practical application because typically a server should be able to handle multiple clients simultaneously and runs indefinitely. So let's look at how you can extend the previous server so that it can handle multiple clients simultaneously.

To do so, you can create a class named Client and code it as follows:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net.Sockets;

namespace Server {

 class Client {

  //---create a TCPClient object---

  TcpClient _client = null;

  //---for sending/receiving data---

  byte[] buffer;

  //---called when a client has connected---

  public Client(TcpClient client) {

   _client = client;

   //---start reading data asynchronously from the client---

   buffer = new byte[_client.ReceiveBufferSize];

   _client.GetStream().BeginRead(

    buffer, 0, _client.ReceiveBufferSize, receiveMessage, null);

  }

  public void receiveMessage(IAsyncResult ar) {

   int bytesRead;

   try {

    lock (_client.GetStream()) {

     //---read from client---

     bytesRead = _client.GetStream().EndRead(ar);

    }

    //---if client has disconnected---

    if (bytesRead < 1) return;

    else {

     //---get the message sent---

     string messageReceived =

      ASCIIEncoding.ASCII.GetString(buffer, 0, bytesRead);

     Console.WriteLine('Received : ' + messageReceived);

     //---write back the text to the client---

     Console.WriteLine('Sending back : ' + messageReceived);

     byte[] dataToSend =

      ASCIIEncoding.ASCII.GetBytes(messageReceived);

     _client.GetStream().Write(dataToSend, 0, dataToSend.Length);

    }

    //---continue reading from client---

    lock (_client.GetStream()) {

     _client.GetStream().BeginRead(

      buffer, 0, _client.ReceiveBufferSize, receiveMessage, null);

    }

   } catch (Exception ex) {

    Console.WriteLine(ex.ToString());

   }

  }

 }

}

Here, the constructor of the Client class takes in a TcpClient object and starts to read from it asynchronously using the receiveMessage() method (via the BeginRead() method of the NetworkStream object). Once the incoming data is read, the constructor continues to wait for more data.

To ensure that the server supports multiple users, you use a TcpListener class to listen for incoming client connections and then use an infinite loop to accept new connections. Once a client is connected, you create a new instance of the Client object and continue waiting for the next client. So the Main() function of your application now looks like this:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net;

using System.Net.Sockets;

namespace Server {

 class Program {

  const int PORT_NO = 5000;

  const string SERVER_IP = '127.0.0.1';

  static void Main(string[] args) {

   //---listen at the specified IP and port no.---

   IPAddress localAddress = IPAddress.Parse(SERVER_IP);

   TcpListener listener = new TcpListener(localAddress, PORT_NO);

   Console.WriteLine('Listening...');

   listener.Start();

   while (true) {

    //---incoming client connected---

    Client user = new Client(listener.AcceptTcpClient());

   }

  }

 }

}

Figure 11-5 shows the server with two clients connected to it.

Figure 11-5 

Вы читаете C# 2008 Programmer's Reference
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату