网络编程

一、基础概念

1-1 TCP面向连接

TCP了解基础
 1.面向连接的(Connection-oriented)的,也就是两个远程主机(或者叫进程,远程通信实际上是进程之间的通信,进程是指运行中的程序)必须进行一个握手过程

TCP握手
 2. TCP是全双工的,就是进程A和进程B连接后,进程A可以向进程B传递信息,同时进程B也可以向进程A传递信息。

 3. TCP有个特性,称为可靠的数据传输,连接建立后,数据的发送一定能够到达,并且是有序的。

TCP还有个重要的概念是套接字(Socket),在OSI(Open System Interconnect,开放式系统互联)网络七层协议,TCP属于传输层协议。通过套接字,可以从应用程序中获取来自于传输层的数据。套接字像是传输层的一扇门,应用程序通过这扇门向远程发送数据,或者接收来自远程的数据。这个门后面的事情,比如消息是如何传递的、是如何保证可靠性的,开发者不需要关心,这属于网络底层的事情。下图为套接字的作用:
套接字的作用

1-2 即时通信程序的三种模式

 网络编程的最常见应用就是即时通信程序。其中即时通信程序有三种模式:点对点广播服务器中央服务器

1-2-1 点对点

点对点:每台计算机即是客户端也是服务器,因为它需要端口的监听

这种模式的难点:各个主机之间如何知道其他主机的存在?通常做法是当某一主机上线,通过UDP协议进行一个IP广播(IP Broadcasting),使用这种方式通知其他主机自己已上线并说明位置,收到广播主机发回的一个应答,此时主机自己便知道其他主机的存在,然后便可以进行连接和通信。
点对点模式

1-2-2 广播服务器

广播服务器 由服务器专门进行广播。服务器保持监听端口状态,当有主机上线时,首先连接至服务器,服务器在收到连接后,将该主机的IP地址和端口号广播给其他在线主机(图中用虚线表示)。这样其他主机即知道该主机已上线,并知道主机IP和端口号,可以与主机直接进行连接并进行通话,不用经过服务器(用实线表示)。因此,在使用这种模式,各个主机仍需要保持对端口的侦听。

广播服务器模式

其中广播服务器模式 解决了点对点模式的判断有多少主机在线的问题。

1-2-3 中央服务器

中央服务器模式最简单并且最实用,其中与广播服务器模式有点类似。区别是,每台主机在上线时就与服务器建立了连接,主机之间并不建立连接。如果主机A向主机B发送消失时,通过的路径是 主机A–>服务器–>主机B,通过这种模式,各个主机不需要对端口进行侦听,只需要服务器对端口进行侦听

如果主机A想要传输的是一个比较大文件(例如图片、文件)给主机B,主机A可以与主机B之间可以搭建一个临时的连接(用虚线表示),传输完成后,关闭该连接。
中央服务器
除此以外,由于消息都经过服务器,因此服务器还可以缓存主机间的对话,即当主机A发往主机B时,如果主机B已经离线,则服务器可以对消息进行缓存,当主机B再次连接服务器时,服务器自动将缓存的消息发给主机B。

二、基本操作

该例子采用第三种模式,中央服务器模式。

2-1 服务端与一个客户端

2-1-1 服务端

首先开启对本地计算机上某一端口的侦听。创建一个控制台应用程序,命名为ServerConsole,代表服务端。

static void Main(string[] args)
{
    Console.WriteLine("Server is running");

    IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });
    // 获得IPAdress 对象的另外几种常用方法:
    // IPAddress ip = IPAddress.Parse("127.0.01");
    // 监听服务器的IP 与端口
    TcpListener listener = new TcpListener(ip, 8500);
    // 开启监听
    listener.Start();
    Console.WriteLine("Start Listing...");
 
    // 获取一个连接,中断方法
    TcpClient remoteClient = listener.AcceptTcpClient();
    Console.WriteLine("Client Connected! Local:{0}<--Client:{1}", remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint);

    Console.WriteLine("\n\n 输入\"Q\"键退出。");
    ConsoleKey key;
    do
    {
        key = Console.ReadKey(true).Key;
    } while (key != ConsoleKey.Q);
}

创建TcpListener实例开启了8500端口的侦听:

服务端执行结果
127.0.0.1是本地计算机IP地址。打开cmd命令提示符,输入 Netstat -a 查看计算机所有活动连接的状态。

提示
 在打开对端口侦听以后,需要对程序进行阻塞操作,例如:Console.ReadKey(),使代码不会执行到末尾而结束,从而cmd命令提示符 捕捉不到8500端口号。
listener.AcceptTcpClient() 获取与一个客户端的连接,返回一个TcpClient类型实例这个方法是 同步方法,调用它之后,会一直等待某个客户端连接,否则会一直等下去。
侦听端口

2-1-2 客户端

服务器开启侦听之后,便可以创建客户端与它连接。
创建一个控制台应用程序,命名为ClientConsole,代表客户端。

static void Main(string[] args)
{
    Console.WriteLine("Client isRunning.....");

    TcpClient client = new TcpClient();

    try
    {
        // 与服务器建立链接 - 握手
        client.Connect(IPAddress.Parse("127.0.0.1"), 8500);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        return;
    }
    // 打印连接到的服务端信息
    Console.WriteLine("Server Connected! Local:{0}-->Server:{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);

    Console.WriteLine("\n\n输入\"Q\"停止程序");
    ConsoleKey key;
    do
    {
        key = Console.ReadKey(true).Key;
    } while (key != ConsoleKey.Q);
}

运行结果:
服务端客户端执行结果

查看侦听端口:
侦听端口

可以看出几个重要信息:

  • 端口8500和端口57077 建立连接。
  • 端口8500与一个客户端建立一个连接后,仍然继续保持在侦听状态。说明,一个端口可以建立多个与远程端口的连接。

2-2 服务端与多个客户端

2-2-1 服务端

修改服务端代码,使侦听并输出连接多个客户端信息:

static void Main(string[] args)
{
    Console.WriteLine("Server is running");

    IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });
    // 监听服务器的IP 与端口
    TcpListener listener = new TcpListener(ip, 8500);
    // 开启监听
    listener.Start();
    Console.WriteLine("Start Listing...");

	while (true)
    {
	    // 获取一个连接,中断方法
        TcpClient remoteClient = listener.AcceptTcpClient();
        Console.WriteLine("Client Connected! Local:{0}<--Client:{1}", remoteClient.Client.LocalEndPoint, remoteClient.Client.RemoteEndPoint);
     }

    Console.WriteLine("\n\n 输入\"Q\"键退出。");
    ConsoleKey key;
    do
    {
        key = Console.ReadKey(true).Key;
    } while (key != ConsoleKey.Q);
}

其中,While(true)看上去是一个死循环,但并不会使计算机的系统资源迅速耗尽,其中AcceptTcpClient()方法没有收到客户端的连接之前,是不会继续执行的,它的大部分时间都在等待。

2-2-2 客户端

static void Main(string[] args)
{
    Console.WriteLine("Client isRunning.....");

    TcpClient client;
    for (int i = 0; i < 3; i++)
    {
    	try
        {
        	// 一个new实例化、有一个套接字,只能与远程服务器连接一次
            client = new TcpClient();
            // 与服务器建立链接 - 握手
            client.Connect(IPAddress.Parse("127.0.0.1"), 8500);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return;
        }
    	// 打印连接到的服务端信息
    	Console.WriteLine("Server Connected! Local:{0}-->Server:{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);
	}

    Console.WriteLine("\n\n输入\"Q\"停止程序");
    ConsoleKey key;
    do
    {
    	key = Console.ReadKey(true).Key;
    } while (key != ConsoleKey.Q);
}

执行结果:
执行结果
查看侦听端口:
侦听端口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值