65.9K
CodeProject 正在变化。 阅读更多。
Home

一个服务器支持多客户端 - .NET(C#)套接字编程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.15/5 (16投票s)

2012年12月18日

CPOL

5分钟阅读

viewsIcon

138086

downloadIcon

12031

一个关于.NET(C#)套接字编程的示例,支持一个服务器连接多个客户端。

 

介绍 

在本文中,我将不侧重于.NET套接字编程的基础知识,因为已经有很多非常有用的文章涵盖了基础知识(例如 套接字编程入门C#中的套接字 等),而是侧重于那些有用的文章未涵盖的部分,即“如何开发一个能够被任意数量客户端连接的套接字服务器程序!”,要了解如何实现这一点,请阅读本文的其余部分。

背景

我再次强调,这不是关于基础知识的,你可以在别处查找它们,所以本文的背景知识应该是你已经搜索过“.NET套接字编程基础”。

使用代码

解决方案包含两个项目

  1. 服务器和
  2. 客户端

两者都是控制台应用程序(使用 Visual Studio 2010 开发的 .NET Framework 2.0)。首先我将演示服务器代码,然后是客户端代码,因为后者要简单得多。

服务器代码

正如我在引言部分所述,本文的目的是让你了解如何为服务器套接字程序开发多客户端能力。要实现这个目标,你绝对需要了解C#中的线程概念,这里我同样不会深入讲解C#中的线程是什么以及如何与它们交互,我假设你已经熟悉它们了,毕竟你可以通过谷歌搜索并找出它们的工作原理。我将讲解如何使用线程来处理多客户端能力。考虑到我们的服务器上的每个客户端能够连接到服务器并与之建立连接,我们需要使用“AcceptSocket()”方法,因此,要让多个客户端能够连接到服务器并与之建立连接,我们需要为所需的客户端数量使用相同数量的AcceptSocket()方法。为了实现这一点,我将在开始时从服务器程序接收客户端数量,然后通过使用线程,为该数量的客户端建立相同数量的线程。以下是我的做法,在main方法中:

        tcpListener.Start();
        Console.WriteLine("************This is Server program************");
        Console.WriteLine("Hoe many clients are going to connect to this server?:");
        int numberOfClientsYouNeedToConnect =int.Parse( Console.ReadLine());
        for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
        {
            Thread newThread = new Thread(new ThreadStart(Listeners));
            newThread.Start();
        } 

从上面可以看到,我首先接收客户端数量,然后定义该数量的线程,其余工作由下面所示的Listeners方法处理。
这样的内容。

static void Listeners()
    {

        Socket socketForClient = tcpListener.AcceptSocket();
        if (socketForClient.Connected)
        {
            Console.WriteLine("Client:"+socketForClient.RemoteEndPoint+" now connected to server.");
            NetworkStream networkStream = new NetworkStream(socketForClient);
            System.IO.StreamWriter streamWriter =
            new System.IO.StreamWriter(networkStream);
            System.IO.StreamReader streamReader =
            new System.IO.StreamReader(networkStream);

            ////here we send message to client
            //Console.WriteLine("type your message to be recieved by client:");
            //string theString = Console.ReadLine();
            //streamWriter.WriteLine(theString);
            ////Console.WriteLine(theString);
            //streamWriter.Flush();

            
            
            //here we recieve client's text if any.
            while (true)
            {
                string theString = streamReader.ReadLine();
                Console.WriteLine("Message recieved by client:" + theString);
                if (theString == "exit")
                    break;
            }
            streamReader.Close();
            networkStream.Close();
            streamWriter.Close();
            

        }
        socketForClient.Close();
        Console.WriteLine("Press any key to exit from server program");
        Console.ReadKey();
    } 

在上面的代码中,只有三个部分对理解这个想法至关重要。我已经将它们加粗了。

  • AcceptSocket()
  • RemoteEndPoint.ToString()
  • streamReader.ReadLine()
不用说AcceptSocket()的作用(参考我在引言部分介绍的基础文章)。请注意,AcceptSocket()方法是必不可少的,因为它扮演着接受客户端请求的角色。RemoteEndPoint基本上定义了连接到服务器的客户端的唯一标识,标识符格式为:IP地址:端口号。最后,streamReader.ReadLine()的作用是等待并阻塞其余执行,直到它从已连接的客户端接收到消息。如果你注意到上面的代码,你会看到我将其放在一个While(true)循环中,这是因为我希望服务器能够接收来自客户端的尽可能多的消息,直到收到来自客户端的exit消息,这会指示服务器结束与该客户端的连接。由于此代码在与主应用程序不同的线程下运行,当最后一个客户端连接并发出退出消息后,整个服务器应用程序将终止。为了更清楚地说明这一点,最好举个例子。假设你想让服务器程序处理2个客户端。你首先需要执行服务器应用程序,然后说我想让2个客户端能够连接到服务器应用程序,然后打开2个客户端程序(通过点击两次client.exe文件),然后开始玩,最后,当你希望退出这两个客户端时,只需为它们分别输入“exit”,然后在服务器端“按任意键”两次,就完成了。很简单!

现在我们来看看客户端代码。

客户端代码 

正如我之前提到的,客户端代码比服务器端简单得多,你只需要连接到服务器程序的指定IP地址和端口。以下是我如何做到的:

static public void Main(string[] Args)
    {
        TcpClient socketForServer;
        try
        {
            socketForServer = new TcpClient("localHost", 10);
        }
        catch
        {
            Console.WriteLine(
            "Failed to connect to server at {0}:999", "localhost");
            return;
        }
       
        NetworkStream networkStream = socketForServer.GetStream();
        System.IO.StreamReader streamReader =
        new System.IO.StreamReader(networkStream);
        System.IO.StreamWriter streamWriter =
        new System.IO.StreamWriter(networkStream);
        Console.WriteLine("*******This is client program who is connected to localhost on port No:10*****");
        
        try
        {
            string outputString;
            // read the data from the host and display it
            {
                //outputString = streamReader.ReadLine();
                //Console.WriteLine("Message Recieved by server:" + outputString);

                //Console.WriteLine("Type your message to be recieved by server:");
                Console.WriteLine("type:");
                string str = Console.ReadLine();
                while (str != "exit")
                {
                    streamWriter.WriteLine(str);
                    streamWriter.Flush();
                    Console.WriteLine("type:");
                    str = Console.ReadLine();
                }
                if (str == "exit")
                {
                    streamWriter.WriteLine(str);
                    streamWriter.Flush();
                   
                }
                
            }
        }
        catch
        {
            Console.WriteLine("Exception reading from Server");
        }
        // tidy up
        networkStream.Close();
        Console.WriteLine("Press any key to exit from client program");
        Console.ReadKey();
    }  

与服务器代码一样,这里又有三个主要部分需要注意:

  1. new TcpClient("localhost" , 10)
  2. streamWriter.WriteLine(str)
  3. streamWrite.Flush()

首先,你需要为客户端代码定义服务器的位置,在这里我们说它位于本地计算机(localhost或127.0.0.1),然后你应该说明服务器正在监听哪个端口号的消息:这是通过new TcpClient("localhost", 10)完成的。顺便说一下,10是端口号。

其次,你需要与服务器通信,这是通过streamWriter.WriteLine(str)命令完成的,请注意,当streamWriter.Flush()执行时,服务器才会收到你的消息。

以上就是全部内容,希望你已经明白了。

完整的服务器和客户端代码

由于我是发布完整代码的作者之一,因此你可以从下方获取客户端和服务器代码。

服务器代码: (program.cs) 

using System;
using System.Net.Sockets;
using System.Threading;
public class AsynchIOServer
{
    static TcpListener tcpListener = new TcpListener(10);

    //static void Listeners()
    //{

    //    Socket socketForClient = tcpListener.AcceptSocket();
    //    if (socketForClient.Connected)
    //    {
    //        Console.WriteLine("Client now connected to server.");
    //        NetworkStream networkStream = new NetworkStream(socketForClient);
    //        System.IO.StreamWriter streamWriter =
    //        new System.IO.StreamWriter(networkStream);
    //        System.IO.StreamReader streamReader =
    //        new System.IO.StreamReader(networkStream);

    //        //here we send message to client
    //        Console.WriteLine("type your message to be recieved by client:");
    //        string theString = GetData();
    //        streamWriter.WriteLine(theString);
    //        //Console.WriteLine(theString);
    //        streamWriter.Flush();

    //        //here we recieve client's text if any.
    //        theString = streamReader.ReadLine();
    //        Console.WriteLine("Message recieved by client:" + theString);
    //        streamReader.Close();
    //        networkStream.Close();
    //        streamWriter.Close();
    //    }
    //    socketForClient.Close();
    //    Console.WriteLine("Press any key to exit from server program");
    //    Console.ReadKey();
    //}


    static void Listeners()
    {

        Socket socketForClient = tcpListener.AcceptSocket();
        if (socketForClient.Connected)
        {
            Console.WriteLine("Client:"+socketForClient.RemoteEndPoint+" now connected to server.");
            NetworkStream networkStream = new NetworkStream(socketForClient);
            System.IO.StreamWriter streamWriter =
            new System.IO.StreamWriter(networkStream);
            System.IO.StreamReader streamReader =
            new System.IO.StreamReader(networkStream);

            ////here we send message to client
            //Console.WriteLine("type your message to be recieved by client:");
            //string theString = Console.ReadLine();
            //streamWriter.WriteLine(theString);
            ////Console.WriteLine(theString);
            //streamWriter.Flush();

            //while (true)
            //{
            //here we recieve client's text if any.
            while (true)
            {
                string theString = streamReader.ReadLine();
                Console.WriteLine("Message recieved by client:" + theString);
                if (theString == "exit")
                    break;
            }
            streamReader.Close();
            networkStream.Close();
            streamWriter.Close();
            //}

        }
        socketForClient.Close();
        Console.WriteLine("Press any key to exit from server program");
        Console.ReadKey();
    }
   
    public static void Main()
    {
        //TcpListener tcpListener = new TcpListener(10);
        tcpListener.Start();
        Console.WriteLine("************This is Server program************");
        Console.WriteLine("Hoe many clients are going to connect to this server?:");
        int numberOfClientsYouNeedToConnect =int.Parse( Console.ReadLine());
        for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
        {
            Thread newThread = new Thread(new ThreadStart(Listeners));
            newThread.Start();
        }

       
       
        //Socket socketForClient = tcpListener.AcceptSocket();
        //if (socketForClient.Connected)
        //{
        //    Console.WriteLine("Client now connected to server.");
        //    NetworkStream networkStream = new NetworkStream(socketForClient);
        //    System.IO.StreamWriter streamWriter =
        //    new System.IO.StreamWriter(networkStream);
        //    System.IO.StreamReader streamReader =
        //    new System.IO.StreamReader(networkStream);

        //    ////here we send message to client
        //    //Console.WriteLine("type your message to be recieved by client:");
        //    //string theString = Console.ReadLine();
        //    //streamWriter.WriteLine(theString);
        //    ////Console.WriteLine(theString);
        //    //streamWriter.Flush();

        //    //while (true)
        //    //{
        //        //here we recieve client's text if any.
        //    while (true)
        //    {
        //        string theString = streamReader.ReadLine();
        //        Console.WriteLine("Message recieved by client:" + theString);
        //        if (theString == "exit")
        //            break;
        //    }
        //        streamReader.Close();
        //        networkStream.Close();
        //        streamWriter.Close();
        //    //}
           
        //}
        //socketForClient.Close();
        //Console.WriteLine("Press any key to exit from server program");
        //Console.ReadKey();
    }
}
 

 

客户端代码: (program.cs) 

using System;
using System.Net.Sockets;
using System.Threading;
public class Client
{
    static public void Main(string[] Args)
    {
        TcpClient socketForServer;
        try
        {
            socketForServer = new TcpClient("localHost", 10);
        }
        catch
        {
            Console.WriteLine(
            "Failed to connect to server at {0}:999", "localhost");
            return;
        }
       
        NetworkStream networkStream = socketForServer.GetStream();
        System.IO.StreamReader streamReader =
        new System.IO.StreamReader(networkStream);
        System.IO.StreamWriter streamWriter =
        new System.IO.StreamWriter(networkStream);
        Console.WriteLine("*******This is client program who is connected to localhost on port No:10*****");
        
        try
        {
            string outputString;
            // read the data from the host and display it
            {
                //outputString = streamReader.ReadLine();
                //Console.WriteLine("Message Recieved by server:" + outputString);

                //Console.WriteLine("Type your message to be recieved by server:");
                Console.WriteLine("type:");
                string str = Console.ReadLine();
                while (str != "exit")
                {
                    streamWriter.WriteLine(str);
                    streamWriter.Flush();
                    Console.WriteLine("type:");
                    str = Console.ReadLine();
                }
                if (str == "exit")
                {
                    streamWriter.WriteLine(str);
                    streamWriter.Flush();
                   
                }
                
            }
        }
        catch
        {
            Console.WriteLine("Exception reading from Server");
        }
        // tidy up
        networkStream.Close();
        Console.WriteLine("Press any key to exit from client program");
        Console.ReadKey();
    }

    private static string GetData()
    {
        //Ack from sql server
        return "ack";
    }
}

关注点

我非常乐意听取关于该主题的其他任何想法。


© . All rights reserved.