C#ソケット1を学ぶ - あなたはまた、チャットプログラムを書くことができます

オリジナル: - C#ソケット1を学ぶあなたはまた、チャットプログラムを書くことができます

ブリーフ

私たちは毎日、ソフトウェアの作業を行うが、ネットワークから切り離すことができない、ネットワークプロトコルの詳細は接続できない、と誰もが理解するだろう。私は今日に来て、私たちは、ソケットを一緒に勉強して、簡単なチャットプログラムを書きます。

いくつかの基本的なクラス

初日我々は、確立されたTCP接続されているWebページの情報が使用されているアクセスにHTTP / HTTPSプロトコル・ブラウザを開き、HTTP。TCPは、ソケットの底部を介して通信が行われます。だから、それらの間の抽象関係は以下のとおりです。

私たちは、その後、さらに上のおなじみのHttpClientとそうであり、TcpListener、れるtcpClient、NetworkStreamを持っているTCP関連の上に、さらにその後、ソケットプログラミングIPEndPoint、DNS、たIPAddressおよび他のカテゴリを学ぶために時間を使用する必要がある、とあります。
次のようにIPEndPoint、DNSは、たIPAddress基本的な役割は次のとおりです。

//根据DNS获取域名绑定的IP
foreach (var address in Dns.GetHostEntry("www.baidu.com").AddressList)
{
    Console.WriteLine($"百度IP:{address}");
}

//字符串转IP地址
IPAddress ipAddress = IPAddress.Parse("192.168.1.101");

//通过IP和端口构造IPEndPoint对象,用于远程连接
//通过IP可以确定一台电脑,通过端口可以确定电脑上的一个程序
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 80);

ソケットを使って書かれたチャットプログラム

私たちは、最初のソケットで始まります。
ソケット通信を実現するために、サーバーを聞いて持って来て、その後、クライアントへの接続があり、その後、クライアントとサーバーは、最大通信することができます。次のように:

次のようにサーバー・コードは次のとおりです。

//1 创建Socket对象
socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//2 绑定ip和端口
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEndPoint = new IPEndPoint(ip, 50001);
socketServer.Bind(ipEndPoint);

//3、开启侦听(等待客户机发出的连接),并设置最大客户端连接数为10
socketServer.Listen(10);

//4、【阻塞】,等待客户端连接
Socket newSocket = socketServer.Accept();

//5、【阻塞】,等待读取客户端发送过来的数据
byte[] data = new byte[1024 * 1024];
int readLeng = newSocket.Receive(data, 0, data.Length, SocketFlags.None);

//6、读取数据
var msg = Encoding.UTF8.GetString(data, 0, readLeng);

クライアントコードは以下のように:

//1 创建Socket对象
socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//2 连接到服务端
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEndPoint = new IPEndPoint(ip, 50001);
socketClient.Connect(ipEndPoint);

//3 发送消息到服务端
socketClient.Send(Encoding.UTF8.GetBytes("你好,农码一生"));

これは、我々はサービスのサービス終了をオンにすることができ、そしてクライアントがメッセージを送っ受け入れること。
しかし、大きな問題があると、サーバはクライアントの接続を確立し、クライアントから送信されたメッセージを受け取ることができます。あなたがより多くのクライアントを接続し、多数のメッセージを受信したい場合は、サーバー・コードは二つの場所にブロックされているスレッドを開き、ループ内で行くには別のパッケージを必要としています。
次のようにサーバーコードが修正さ:

void .... ()
{
    //1 创建Socket对象
    socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    //2 绑定ip和端口
    IPAddress ip = IPAddress.Parse("127.0.0.1");
    IPEndPoint ipEndPoint = new IPEndPoint(ip, 50001);
    socketServer.Bind(ipEndPoint);
    
    //3、开启侦听(等待客户机发出的连接),并设置最大客户端连接数为10
    socketServer.Listen(10);
    
    //开启新的线程,循环等待新的客户端连接
    Task.Run(() => { Accept(socketServer); });
}

void Accept(Socket socket)
{
    while (true)
    {
        //4、【阻塞】,等待客户端连接
        Socket newSocket = socket.Accept();
        
        //开启新的线程,循环等待接收新的数据
        Task.Run(() => { Receive(newSocket); });
    }
}

void Receive(Socket newSocket)
{
    while (true)
    {
        //5、【阻塞】,等待读取客户端发送过来的数据
        byte[] data = new byte[1024 * 1024];
        int readLeng = newSocket.Receive(data, 0, data.Length, SocketFlags.None);
        
        //6、读取数据
        var msg = Encoding.UTF8.GetString(data, 0, readLeng); 
    }
} 

これは、サーバが複数の接続を受け入れ、複数のクライアントのクライアントから送信されたメッセージを受信することができます。しかし、我々は、顧客サービス側がサーバに送信されたメッセージを受信することができ、あなたがこの時にそれを自分で試すことができる必要があるかもしれません。記事の最後には、完全なコードの参照を提供します。

注意:
用Socket来编写聊天软件是长连接,有状态的。不确定服务端什么时候会发送消息过来,我们也可以连续发送消息而不响应。所以,对于消息的接收就需要开一个新的线程循环接收。
而对于HTTP来说,虽然它是也是通过TCP建立的通信,但在数据请求完毕后会马上关闭连接,这个过程很短。每次访问都会建立一个新的连接,是无状态的。
对于浏览器来说是一问一答的形式,先发送请求(Send),然后接收响应(Receive)所以就可以做到不开启新的线程,直接有序的同步的完成。这个在下一篇《模拟浏览器的请求和服务端的响应》会具体分析。

TCPを使って書かれたチャットプログラム

虽然上面我们利用Socket类实现了一个简单的聊天程序,但是微软觉得Socket太复杂。为了让你们早点干完活,早点下班,于是又在Socket的基础上有封装了两个相关的类TcpListener、TcpClient。
利用TcpListener、TcpClient来实现同上面相同的功能。
服务端代码:

void ...()
{
    //1 开启监听
    TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9999);
    tcpListener.Start(10); //最多同时接收10个用户连接
    
    //开启一个线程,循环等待客户端的连接
    Task.Run(() => { Accept(); });
}


//等待客户端的连接
void Accept()
{
    while (true)
    {
        //2 【阻塞】等待客户端的连接
        TcpClient tcpClient = tcpListener.AcceptTcpClient();
        NetworkStream networkStream = tcpClient.GetStream();
        
        //开启一个新的线程 等待新的消息
        Task.Run(() => { Read(networkStream, tcpClient); });
    }
}

//接收消息
void Read(NetworkStream networkStream)
{
    while (true)
    { 
        byte[] buffer = new byte[1024 * 1024];
        //3 【阻塞】等待接收新的消息
        var readLen = networkStream.Read(buffer, 0, buffer.Length);
        var msg  = Encoding.UTF8.GetString(buffer, 0, readLen); 
    }
}

客户端代码:

//1 连接服务端
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text));

//2 发送消息到服务端
byte[] buffer = Encoding.UTF8.GetBytes("你好,农码一生");
networkStream.Write(buffer, 0, buffer.Length);

用TcpListener、TcpClient的实现也算ok了,TcpListener代码写的服务端和Socket通信也是完成没问题的,因为他们最后都是Socket。
对此你有觉得比Socket简单和容易理解?其实我更习惯Socket。

注意:

// 1、断开连接使用
socketClient?.Shutdown(SocketShutdown.Both);
socketClient?.Close();

// 2、服务端需要判断
int readLeng = newSocket.Receive(data, 0, data.Length, SocketFlags.None);
if (readLeng == 0)//客户端断开连接
{
    //停止会话(禁用Socket上的发送和接收,该方法允许Socket对象一直等待,直到将内部缓冲区的数据发送完为止)
    newSocket.Shutdown(SocketShutdown.Both);
    //关闭连接
    newSocket.Close();
    //跳出循环
    return;
}

3、具体请参考文末提供的完整demo

效果图

结束

おすすめ

転載: www.cnblogs.com/lonelyxmas/p/12053905.html