网络编程、TCP通信案例



网络编程入门


软件结构


C/S结构 :全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。

特点: 客户端和服务器是分开的,需要下载客户端,对网络要求相对低,减少服务器压力,相对稳定, 开发和维护成本高


B/S结构 :全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。

特点:没有客户端,只有服务器,不需要下载客户端,直接通过浏览器访问, 对网络要求相对高 ,服务器压力很大,相对不稳定,开发和维护成本低

两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,编写代码实现两台计算机在网络中进行通信的程序。


网络编程三要素


协议

网络通信协议 :通信协议是计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信。这就好比在道路中行驶的汽车一定要遵守交通规则一样,协议中对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守,最终完成数据交换。

java.net 包中提供了两种常见的网络协议的支持:


TCP:传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。


TCP协议特点: 面向连接,传输数据安全,传输速度慢

例如: 村长发现张三家的牛丢了

TCP协议: 村长一定要找到张三,面对面的告诉他他家的牛丢了 打电话: 电话一定要接通,并且是张三接的

连接三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。

  • 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。 你愁啥?

  • 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。我愁你咋地?

  • 第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。你再愁试试

完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以 应用十分广泛,例如下载文件、浏览网页等 。


UDP:用户数据报协议(User Datagram Protocol)。UDP协议是一个面向无连接的协议。传输数据时,不需要建立连接,不管对方端服务是否启动,直接将数据、数据源和目的地都封装在数据包中,直接发送。每个数据包的大小限制在64k以内。它是不可靠协议,因为无连接,所以传输速度快,但是容易丢失数据。日常应用中**,例如视频会议、QQ聊天等。


UDP特点: 面向无连接,传输数据不安全,传输速度快

例如: 村长发现张三家的牛丢了

UDP协议: 村长在村里的广播站广播一下张三家的牛丢了,信息丢失,信息发布速度快


IP地址


IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设备做唯一的编号。相当于每个人的身份证号码。


IP地址分类


IPv4:是一个32位的二进制数,通常被分为4个字节,表示成a.b.c.d 的形式,例如192.168.65.100 。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。

IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。有资料显示,全球IPv4地址在2011年2月分配完毕。

为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题。


常用命令


查看本机IP地址,在控制台输入:

ipconfig

检查网络是否连通,在控制台输入:

ping 空格 IP地址
ping 220.181.57.216
ping www.baidu.com

特殊的IP地址


本机IP地址:127.0.0.1localhost


端口号


网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,那么在网络通信时,如何区分这些进程呢?

如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程(应用程序)了。

端口号:用两个字节表示的整数,它的取值范围是065535**。其中,01023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。 如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。

利用协议+IP地址+端口号 三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。


域名


域名----->绑定了ip地址

域名是唯一的


InetAddress类


InetAddress类的概述

一个该类的对象就代表一个IP地址对象。


InetAddress类的方法

static InetAddress getLocalHost() 获得本地主机IP地址对象

static InetAddress getByName(String host) 根据IP地址字符串或主机名获得对应的IP地址对象

String getHostName();获得主机名

String getHostAddress();获得IP地址字符串


public class Test {
    public static void main(String[] args) throws Exception {
        //- static InetAddress getLocalHost()   获得本地主机IP地址对象
        InetAddress ip1 = InetAddress.getLocalHost();
        System.out.println("ip1:" + ip1);// DESKTOP-U8Q5F96/10.254.4.12

        //- static InetAddress getByName(String host) 根据IP地址字符串或主机名获得对应的IP地址对象
        InetAddress ip2 = InetAddress.getByName("www.baidu.com");
        System.out.println("ip2:" + ip2);// www.baidu.com/14.215.177.38

        //- String getHostName();获得主机名
        System.out.println("ip1的主机名:"+ip1.getHostName());// DESKTOP-U8Q5F96
        System.out.println("ip2的主机名:"+ip2.getHostName());// www.baidu.com

        //- String getHostAddress();获得IP地址字符串
        System.out.println("ip1的ip地址:"+ip1.getHostAddress());// 10.254.4.12
        System.out.println("ip2的ip地址:"+ip2.getHostAddress());// 14.215.177.38

    }
}



TCP通信程序


TCP通信的流程

TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收器端**建立逻辑连接,然后再传输数据。**它提供了两台计算机之间可靠无差错的数据传输。TCP通信过程如下图所示:



TCP协议相关的类


Socket : 一个该类的对象就代表一个客户端程序。

Socket(String host, int port) 根据ip地址字符串和端口号创建客户端Socket对象


注意事项:只要执行该方法,就会立即连接指定的服务器程序,如果连接不成功,则会抛出异常,如果连接成功,则表示三次握手通过。

  • OutputStream getOutputStream(); 获得字节输出流对象

  • InputStream getInputStream();获得字节输入流对象

  • void close();关闭Socket, 会自动关闭相关的流


补充:关闭通过socket获得的流,会关闭socket,关闭socket,同时也会关闭通过socket获得的流


ServerSocket : 一个该类的对象就代表一个服务器端程序。

  • ServerSocket(int port); 根据指定的端口号开启服务器。

  • Socket accept(); 等待客户端连接并获得与客户端关联的Socket对象 如果没有客户端连接,该方法会一直阻塞

  • void close();关闭ServerSocket


TCP通信循环聊天案例


服务器

public class Server {
    public static void main(String[] args) throws Exception{
        // 服务器:
        //1.创建ServerSocket对象,指定端口号 6666
        ServerSocket ss = new ServerSocket(6666);

        //2.调用accept方法接收客户端请求,建立连接,返回Socket对象
        Socket socket = ss.accept(); // 会阻塞,直到客户端连接成功

        // 死循环
        while (true) {
            //3.使用Socket对象获得输入流
            InputStream is = socket.getInputStream();

            //4.读客户端写过来的数据
            byte[] bys = new byte[1024];
            int len = is.read(bys);
            System.out.println("服务器读到客户端的数据是:" + new String(bys, 0, len));

            // 服务器回写数据给客户端
            // 5.使用Socket对象获得输出流
            OutputStream os = socket.getOutputStream();

            // 6.写出数据
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入一个字符串:");
            String msg = sc.nextLine();
            os.write(msg.getBytes());

            // 7.关闭流,释放资源
            // socket.close();
            // ss.close();// 一般服务器是不关
        }
    }
}


客户端

public class Client {
    public static void main(String[] args) throws Exception{
        // 客户端:
        //1.创建Socket对象,指定要连接的服务器的ip地址和端口号
        Socket socket = new Socket("127.0.0.1",6666);

        // 死循环
        while (true) {
            //2.通过Socket对象获得输出流
            OutputStream os = socket.getOutputStream();

            //3.写出字符串数据
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入一个字符串:");
            String msg = sc.nextLine();
            os.write(msg.getBytes());


            // 接收服务器回写的数据
            //4.通过Socket对象获得输入流
            InputStream is = socket.getInputStream();

            //5.读服务器回写的字符串数据
            byte[] bys = new byte[1024];
            int len = is.read(bys);
            System.out.println("客户端读到服务器端回写的数据:"+new String(bys,0,len));

            //6.关闭流,释放资源
            // os.close();
        }
    }
}



文件上传综合案例


使用TCP协议, 通过客户端向服务器上传一个文件


分析

  1. 【客户端】输入流,从硬盘读取文件数据到程序中。

  2. 【客户端】输出流,写出文件数据到服务端。

  3. 【服务端】输入流,读取文件数据到服务端程序。

  4. 【服务端】输出流,写出文件数据到服务器硬盘中。

  5. 【服务端】获取输出流,回写数据。

  6. 【客户端】获取输入流,解析回写数据。


在这里插入图片描述


实现


服务器

public class Server {
    public static void main(String[] args) throws Exception {
        //服务器:
        //1.创建ServerSocket对象,指定端口号
        ServerSocket ss = new ServerSocket(7777);

        // 循环接收请求,建立连接
        while (true){
            //2.调用accept方法接收请求,建立连接,返回Socket对象
            Socket socket = ss.accept();

            // 建立连接之后,就开启线程上传文件
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //4.通过Socket对象获得输入流,关联连接通道
                        InputStream is = socket.getInputStream();

                        //5.创建字节输出流,关联目的地文件路径
                        FileOutputStream fos = new FileOutputStream("file\\bbb\\"+System.currentTimeMillis()+".jpg");

                        //6.定义一个byte数组,用来存储读取到的字节数据
                        byte[] bys = new byte[8192];

                        //7.定义一个int变量,用来存储读取到的字节个数
                        int len;

                        System.out.println("服务开始接收文件...");
                        //8.循环读数据--->连接通道
                        while ((len = is.read(bys)) != -1) {// 卡住
                            //9.在循环中,写出数据
                            fos.write(bys, 0, len);
                        }

                        System.out.println("服务器接收文件完毕了!");
                        //10.通过Socket对象获得输出流
                        OutputStream os = socket.getOutputStream();

                        //11.回写数据给客户端
                        os.write("文件上传成功!".getBytes());

                        //12.关闭流,释放资源
                        fos.close();
                        is.close();
                        // ss.close();
                    }catch (Exception e){

                    }
                }
            }).start();

        }
    }
}


客户端

public class Client {
    public static void main(String[] args) throws Exception{
        //客户端:
        //1.创建Socket对象,指定要连接的服务器的ip地址和端口号
        Socket socket = new Socket("127.0.0.1",7777);

        //2.创建字节输入流,关联数据源文件路径
        FileInputStream fis = new FileInputStream("file\\aaa\\mm.jpg");

        //3.通过Socket对象获得输出流,关联连接通道
        OutputStream os = socket.getOutputStream();

        //4.定义一个byte数组,用来存储读取到的字节数据
        byte[] bys = new byte[8192];

        //5.定义一个int变量,用来存储读取到的字节个数
        int len;

        System.out.println("客户端开始上传文件...");
        //6.循环读数据-->源文件
        while ((len = fis.read(bys)) != -1) {
            //7.在循环中,写出数据
            os.write(bys,0,len);// 最后文件中的字节数据
        }
        /*
            结束不了的原因: 服务器不知道客户端不再写数据过来了,所以服务器会一直等到读取数据
            解决办法: 客户端不再写数据了,就需要告诉服务器
         */
        socket.shutdownOutput();// 终止写出数据,但流没有关闭

        System.out.println("客户端上传文件完毕!");

        //8.通过Socket对象获得输入流
        InputStream is = socket.getInputStream();

        //9.读取服务器回写的数据
        int lens = is.read(bys);// 卡住
        System.out.println("服务器回写的数据:"+new String(bys,0,lens));

        //10.关闭流,释放资源
        os.close();
        fis.close();
    }
}

模拟B\S服务器 扩展


模拟网站服务器,使用浏览器访问自己编写的服务端程序,查看网页效果。


分析

  1. 准备页面数据,web文件夹。

  2. 我们模拟服务器端,ServerSocket类监听端口,使用浏览器访问,查看网页效果

  3. 注意:

    // 1.浏览器工作原理是遇到图片会开启一个线程进行单独的访问,因此在服务器端加入线程技术。
    // 2. 响应页面的时候需要同时把以下信息响应过去给浏览器
    os.write("HTTP/1.1 200 OK\r\n".getBytes());
    os.write("Content-Type:text/html\r\n".getBytes());
    os.write("\r\n".getBytes());
    

实现

public class Server {
    public static void main(String[] args) throws Exception {
        //1.创建ServerSocket对象,指定端口号为8888
        ServerSocket ss = new ServerSocket(8888);

        // 浏览器工作原理是遇到图片会开启一个线程进行单独的访问,因此在服务器端加入线程技术。
        while (true){
            //2.调用accept方法接收请求,建立连接,返回Socket对象
            Socket socket = ss.accept();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //3.通过Socket对象获得输入流
                        InputStream is = socket.getInputStream();

                        //4.通过输入流读取连接通道中的请求数据(浏览器发过来)
                        // byte[] bys = new byte[8192];
                        // int len = is.read(bys);
                        // System.out.println(new String(bys,0,len));
                        InputStreamReader isr = new InputStreamReader(is);
                        BufferedReader br = new BufferedReader(isr);
                        String line = br.readLine();
                        System.out.println("line:" + line);

                        //5.通过请求数据筛选出要访问的页面的路径(file\web\index.html)
                        String[] arr = line.split(" ");
                        String path = arr[1].substring(1);
                        System.out.println("path:"+path);

                        //6.创建字节输入流对象,关联需要访问的页面的路径
                        FileInputStream fis = new FileInputStream(path);

                        //7.通过Socket对象获得输出流,关联连接通道
                        OutputStream os = socket.getOutputStream();

                        //8.定义一个byte数组,用来存储读取到的字节数据
                        byte[] bys = new byte[8192];

                        //9.定义一个int变量,用来存储读取到的字节个数
                        int len;

                        //10.循环读取数据
                        // 响应页面的时候需要同时把以下信息响应过去给浏览器
                        os.write("HTTP/1.1 200 OK\r\n".getBytes());
                        os.write("Content-Type:text/html\r\n".getBytes());
                        os.write("\r\n".getBytes());

                        while ((len = fis.read(bys)) != -1) {
                            //11.在循环中,写数据给浏览器
                            os.write(bys,0,len);
                        }
                        //12.关闭流,释放资源
                        os.close();
                        fis.close();
                        //ss.close();
                    }catch (Exception e){

                    }
                }
            }).start();
        }
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
目录 (1)基本网络编程实例 Winsock实现网络聊天室【\chap1\ChatRoom(Winsock)】 CSocket实现聊天室【\chap1\ChatRoom(Csocket)】 (2)本地计算机网络编程实例 获取计算机的名称和IP地址【\chap2\Local】 获取计算机的子网掩码【\chap2\ Local】 获取计算机的DNS设置【\chap2\ Local】 获取计算机的网卡地址【\chap2\ Local】 获取计算机安装的协议【\chap2\ Local】 获取计算机提供的服务【\chap2\ Local】 获取计算机的所有网络资源【\chap2\ Local】 修改本地计算机的所有网络设置【\chap2\ Local】 获取计算机TCP/IP协议的所有信息【\chap2\ Local】 (3)局域网网络通信编程实例 获取网上邻居【\chap3\Neighbor】 lIP地址和计算机名之间的转换【\chap3\Neighbor】 l映射网络驱动器【\chap3\Neighbor】 l消息发送程序Net Send【\chap3\Neighbor】 l获取局域网内其他计算机的信息【\chap3\ NeighborInfo】 (4)IE编程实例 简单的浏览器的实现【\chap4\MyBrowser】 删除IE相关历史记录【\chap4\DelHistory】 将应用程序加入到IE工具栏【\chap4\AddToToolBar】 超级链接的实现【\chap4\HyperLink】 禁止IE的弹出窗口【\chap4\StopPopup】 禁止浏览某些网站【\chap4\StopTravel】 IE收藏夹【\chap4\ MyBrowser】 创建桌面快捷方式和活动桌面【\chap4\ShortCut】 (5)基本网络编程实例 点对点文件传输【\chap5\Transfer】 大型文件传输【\chap5\Transfer】 端口扫描程序【\chap5\ MyPortScanner】 Finger编程【\chap5\MyFinger】 Sniff编程【\chap5\MySniff】 Internet文件下载【\chap5\ InternetDownload】 (6)网络通信协议编程 FTP协议【\chap6\FTP】 Email协议【\chap6\Email】 ICMP协议【\chap6\ICMP】 RAS协议【\chap6\RAS】 TAPI协议【\chap6\TAPI】 Telnet协议【\chap6\Telnet】 HTTP协议 【\chap6\HTTP】 (7)Modem /串口通信编程 Modem编程【\chap7\Modem】 MSCOMM控件编程【\chap7\MSCOMM】 串口通信API编程【\chap7\MySerialCom】 (8)代理服务器编程实例 Socks 5协议编程【\chap8\Socks5】 HTTP代理服务器【\chap8\HTTP代理服务】 (9)高级网络通信编程实例 串口通信编程实例【\chap9\SerialPort】 网络流量监控【\chap9\NetTraffic】 网站下载【\chap9\ Snag】 网络五子棋系统【\chap9\FiveChess】 语音聊天【\chap9\ ChatRoom】 远程监控【\chap9\RemoteControl】 赠送实例 类似网络蚂蚁的断点续传程序【\Appendix\NetAnts】 网络多播程序【\Appendix\BroadCast】 界面美观的文字聊天程序【\Appendix\Chat】 语音电话【\Appendix\PhoneCall】

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

请叫我阿杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值