20145206《Java程序设计》第10周学习总结

20145206 《Java程序设计》第10周学习总结

博客学习内容总结

什么是网络编程

网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据。程序员所作的事情就是把数据发送到指定的位置,或者接收到指定的数据,这个就是狭义的网络编程范畴。在发送和接收数据时,大部分的程序设计语言都设计了专门的API实现这些功能,程序员只需要调用即可。

计算机网络概述

·路由器和交换机组成了核心的计算机网络,计算机只是这个网络上的节点以及控制等,通过光纤、网线等连接将设备连接起来,从而形成了一张巨大的计算机网络。
·网络最主要的优势在于共享:共享设备和数据,现在共享设备最常见的是打印机。共享数据就是将大量的数据存储在一组机器中,其它的计算机通过网络访问这些数据。
·对于网络编程来说,最主要的是计算机和计算机之间的通信
·网络中的每个设备都会有一个唯一的数字标识,这个就是IP地址。在计算机网络中,现在命名IP地址的规定是IPv4协议,该协议规定每个IP地址由4个0-255之间的数字组成。每个接入网络的计算机都拥有唯一的IP地址,这个IP地址可能是固定的,也可以是动态的。
·由于IP地址不容易记忆,所以为了方便记忆,有创造了另外一个概念——域名(Domain Name)。一个IP地址可以对应多个域名,一个域名只能对应一个IP地址。
·在网络中传输的数据,全部是以IP地址作为地址标识,所以在实际传输数据以前需要将域名转换为IP地址,实现这种功能的服务器称之为DNS服务器,也就是通俗的说法叫做域名解析。
· 当DNS服务器正常工作时,使用IP地址或域名都可以很方便的找到计算机网络中的某个设备,当DNS不正常工作时,只能通过IP地址访问该设备。所以IP地址的使用要比域名通用一些。
·为了让一个计算机可以同时运行多个网络程序,就引入了另外一个概念——端口(port)。有了端口的概念以后,在同一个计算机中每个程序对应唯一的端口,这样一个计算机上就可以通过端口区分发送给每个端口的数据了。在硬件上规定,端口的号码必须位于0-65535之间,每个端口唯一的对应一个网络程序,一个网络程序可以使用多个端口。

网络编程概述

·网络编程就是两个或多个程序之间的数据交换,和普通的单机程序相比,网络程序最大的不同就是需要交换数据的程序运行在不同的计算机上,这样就造成了数据交换的复杂。
·网络通讯基于“请求-响应”模型。也就是通讯的一端发送数据,另外一端反馈数据。
·在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序,简称客户端,而在第一次通讯中等待连接的程序被称作服务器端(Server)程序,简称服务器。一旦通讯建立,则客户端和服务器端完全一样,没有本质的区别。网络编程中的两种程序就分别是客户端和服务器端。这种网络编程的结构被称作客户端/服务器结构,也叫做Client/Server结构,简称C/S结构。
·使用C/S结 构的程序,在开发时需要分别开发客户端和服务器端,这种结构的优势在于由于客户端是专门开发的,所以根据需要实现各种效果,专业点说就是表现力丰富,而服 务器端也需要专门进行开发。但是这种结构也存在着很多不足,例如通用性差,几乎不能通用等。
·在运行很多程序时,没有必要使用专用的客户端,而需要使用通用的客户端,使用浏览器作为客户端的结构被称作浏览器/服务器结构,也叫做Browser/Server结构,简称为B/S结构。使用B/S结构的程序,在开发时只需要开发服务器端即可,这种结构的优势在于开发的压力比较小,不需要维护客户端。但是这种结构也存在着很多不足,例如浏览器的限制比较大,表现力不强,无法进行系统级操作等。
·总之C/S结构和B/S结构是现在网络编程中常见的两种结构,B/S结构其实也就是一种特殊的C/S结构。
·P2P程序是一种特殊的程序,应该一个P2P程序中既包含客户端程序,也包含服务器端程序。一般的手机不能同时使用拨打电话和接听电话的功能,而P2P程序实现了该功能。
·在实际进行数据交换时,为了让接收端理解该数据,那么就需要规定该数据的格式,这个数据的格式就是协议。那么如何来编写协议格式呢?答案是随意。只要按照这种协议格式能够生成唯一的编码,按照该编码可以唯一的解析出发送数据的内容即可。也正因为各个网络程序之间协议格式的不同,所以才导致了客户端程序都是专用的结构。

网络通讯方式

在现有的网络中,网络通讯的方式主要有两种:

1、 TCP(传输控制协议)方式
2、 UDP(用户数据报协议)方式
·在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。而UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得。
·重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则都通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据的传递。使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。

客户端网络编程步骤

客户端一般实现程序界面和基本逻辑实现,客户端的编程主要由三个步骤实现:

1、 建立网络连接
在建立网络连接时需要指定连接到的服务器的IP地址和端口号,建立完成以后,会形成一条虚拟的连接,后续的操作就可以通过该连接实现数据交换了。
2、 交换数据
交换数据严格按照请求响应模型进行,由客户端发送一个请求数据到服务器,服务器反馈一个响应数据给客户端,如果客户端不发送请求则服务器端就不响应。
根据逻辑需要,可以多次交换数据,但是还是必须遵循请求响应模型。
3、 关闭网络连接
在数据交换完成以后,关闭网络连接,释放程序占用的端口、内存等系统资源,结束网络编程。

服务器端网络编程步骤

服务器端一般实现程序的核心逻辑以及数据存储等核心功能。是由四个步骤实现,依次是:

1、 监听端口
服务器端启动以后,不需要发起连接,而只需要监听本地计算机的某个固定端口即可。这个端口就是服务器端开放给客户端的端口,服务器端程序运行的本地计算机的IP地址就是服务器端程序的IP地址。
2、 获得连接
这个连接包含客户端的信息,服务器端和客户端也通过该连接进行数据交换。
3、 交换数据
首先接收客户端发送过来的数据,然后进行逻辑处理,再把处理以后的结果数据发送给客户端。
4、 关闭连接
通过关闭服务器端使得服务器监听的端口以及占用的内存可以释放出来,实现了连接的关闭。

Java网络编程技术

·和网络编程有关的基本API位于java.net包中,该包中包含了基本的网络编程实现,该包是网络编程的基础。

1、InetAddress类
·该类的功能是代表一个IP地址,并且将IP地址和域名相关的操作方法包含在该类的内部。
·代码示例:

 package inetaddressdemo;

import java.net.*;
/**
 * 演示InetAddress类的基本使用
 */
public class InetAddressDemo {
         public static void main(String[] args) {
                   try{
                            //使用域名创建对象
                            InetAddress inet1 = InetAddress.getByName("www.163.com");
                            System.out.println(inet1);
                            //使用IP创建对象
                            InetAddress inet2 = InetAddress.getByName("127.0.0.1");
                            System.out.println(inet2);
                            //获得本机地址对象
                            InetAddress inet3 = InetAddress.getLocalHost();
                            System.out.println(inet3);
                            //获得对象中存储的域名
                            String host = inet3.getHostName();
                            System.out.println("域名:" + host);
                            //获得对象中存储的IP
                            String ip = inet3.getHostAddress();
                            System.out.println("IP:" + ip);
                   }catch(Exception e){}
         }
}

TCP编程

在实际实现时,以java.net.Socket类代表客户端连接,以java.net.ServerSocket类代表服务器端连接。
在程序员实际编程时,只需要指定IP地址和端口号码就可以建立连接了。Java语言无法实现底层的网络嗅探以及获得IP包结构等信息。
在客户端网络编程中,首先需要建立连接,在Java API中以java.net.Socket类的对象代表网络连接,所以建立客户端网络连接,也就是创建Socket类型的对象,该对象代表网络连接。示例如下:

         Socket socket1 = new Socket(“192.168.1.103”,10000);

         Socket socket2 = new Socket(“www.sohu.com”,80);

紧接着的步骤就是按照“请求-响应”模型进行网络数据交换,在Java语言中,数据传输功能由Java IO实现,也就是说只需要从连接中获得输入流和输出流即可,然后将需要发送的数据写入连接对象的输出流中,在发送完成以后从输入流中读取数据即可。示例代码如下:

         OutputStream os = socket1.getOutputStream(); //获得输出流

         InputStream is = socket1.getInputStream();     //获得输入流

最后当数据交换完成以后,关闭网络连接,释放网络连接占用的系统端口和内存等资源,完成网络操作,示例代码如下:

         socket1.close();

一个简单的网络客户端程序示例,该程序的作用是向服务器端发送一个字符串“Hello”,并将服务器端的反馈显示到控制台,数据交换只进行一次,当数据交换进行完成以后关闭网络连接,程序结束。实现的代码如下:

package tcp;
import java.io.*;
import java.net.*;
/**
 * 简单的Socket客户端
 * 功能为:发送字符串“Hello”到服务器端,并打印出服务器端的反馈
 */
public class SimpleSocketClient {
         public static void main(String[] args) {
                   Socket socket = null;
                   InputStream is = null;
                   OutputStream os = null;
                   //服务器端IP地址
                   String serverIP = "127.0.0.1";
                   //服务器端端口号
                   int port = 10000;
                   //发送内容
                   String data = "Hello";
                   try {
                            //建立连接
                            socket = new Socket(serverIP,port);
                            //发送数据
                            os = socket.getOutputStream();
                            os.write(data.getBytes());
                            //接收数据
                            is = socket.getInputStream();
                            byte[] b = new byte[1024];
                            int n = is.read(b);
                            //输出反馈数据
                            System.out.println("服务器反馈:" + new String(b,0,n));
                   } catch (Exception e) {
                            e.printStackTrace(); //打印异常信息
                   }finally{
                            try {
                                     //关闭流和连接
                                     is.close();
                                     os.close();
                                     socket.close();
                            } catch (Exception e2) {}
                   }
         }
}

如果需要强制发送,可以调用输出流对象中的flush方法实现。
在控制台下面编译和运行该代码,依次输入编译和运行命令:

  javac –d . SimpleSocketClient.java

         java tcp.SimpleSocketClient

TCP类型的服务器端的编写。实现服务器端监听的代码为:

         ServerSocket ss = new ServerSocket(10000);

实现获得连接的代码是:

         Socket socket = ss.accept();

accept和前面IO部分介绍的read方法一样,都是一个阻塞方法,也就是当无连接时,该方法将阻塞程序的执行,直到连接到达时才执行该行代码。
最后,在服务器端通信完成以后,关闭服务器端连接。实现的代码为:

         ss.close();

echo服务器端实现的功能就是将客户端发送的内容再原封不动的反馈给客户端。实现的代码如下:

         package tcp;

import java.io.*;
import java.net.*;
/**
 * echo服务器
 * 功能:将客户端发送的内容反馈给客户端
 */
public class SimpleSocketServer {
         public static void main(String[] args) {
                   ServerSocket serverSocket = null;
                   Socket socket = null;
                   OutputStream os = null;
                   InputStream is = null;
                   //监听端口号
                   int port = 10000;
                   try {
                            //建立连接
                            serverSocket = new ServerSocket(port);
                            //获得连接
                            socket = serverSocket.accept();
                            //接收客户端发送内容
                            is = socket.getInputStream();
                            byte[] b = new byte[1024];
                            int n = is.read(b);
                            //输出
                            System.out.println("客户端发送内容为:" + new String(b,0,n));
                            //向客户端发送反馈内容
                            os = socket.getOutputStream();
                            os.write(b, 0, n);
                   } catch (Exception e) {
                            e.printStackTrace();
                   }finally{
                            try{
                                     //关闭流和连接
                                     os.close();
                                     is.close();
                                     socket.close();
                                     serverSocket.close();
                            }catch(Exception e){}
                   }
         }
}

1、如何复用Socket连接?
拨通一次电话以后多次对话,这就是复用客户端连接。那么如何实现建立一次连接,进行多次数据交换呢?其实很简单,建立连接以后,将数据交换的逻辑写到一个循环中就可以了。这样只要循环不结束则连接就不会被关闭。按照客户端实现的逻辑,也可以复用服务器端的连接,实现的原理也是将服务器端的数据交换逻辑写在循环中即可.
2、如何使服务器端支持多个客户端同时工作?
·如果需要同时支持多个客户端,则必须使用前面介绍的线程的概念。简单来说,也就是当服务器端接收到一个连接时,启动一个专门的线程处理和该客户端的通讯。
·MulThreadSocketServer类实现服务器端控制,实现接收客户端连接,然后开启专门的逻辑线程处理该连接,LogicThread类实现对于一个客户端连接的逻辑处理,将处理的逻辑放置在该类的run方法中。当任何一个客户端连接到达时,都开启一个专门的线程处理,通过多个线程支持多个客户端同时处理。
·不能无限制的创建线程对象,而且频繁的创建线程对象效率也比较低,所以程序中都实现了线程池来提高程序的执行效率。
·在程序启动时首先把需要个数的线程对象创建好,然后当客户端连接到达时从池中取出一个已经创建完成的线程对象使用即可。当客户端连接关闭以后,将该线程对象重新放入到线程池中供其它的客户端重复使用。

UDP方式的网络编程

·UDP(User Datagram Protocol),中文意思是用户数据报协议,方式类似于发短信息,是一种物美价廉的通讯方式,使用该种方式无需建立专用的虚拟连接,由于无需建立专用的连接,所以对于服务器的压力要比TCP小很多,所以也是一种常见的网络编程方式。
·最大的不足是传输不可靠。必须要求可靠传输的信息一般使用TCP方式实现,一般的数据才使用UDP方式实现。
·需要使用的类还是包含在java.net包中。
· 在Java API中,实现UDP方式的编程,包含客户端网络编程和服务器端网络编程,主要由两个类实现,分别是:

1、 DatagramSocket
DatagramSocket类实现“网络连接”,包括客户端网络连接和服务器端网络连接。DatagramSocket实现的是发送数据时的发射器,以及接收数据时的监听器的角色。
2、 DatagramPacket
DatagramPacket类实现对于网络中传输的数据封装。IO编程在UDP方式的网络编程中变得不是必须的内容,结构也要比TCP方式的网络编程简单一些。
UDP客户端编程涉及的步骤也是4个部分:
<1>建立连接
只需要建立一个连接对象即可,不需要指定服务器的IP和端口号码:

 DatagramSocket ds = new DatagramSocket();

当然,可以通过制定连接使用的端口号来创建客户端连接:

 DatagramSocket ds = new DatagramSocket(5000);

<2>发送数据
在UDP方式的网络编程中,IO技术不是必须的,在发送数据时,需要将需要发送的数据内容首先转换为byte数组,然后将数据内容、服务器IP和服务器端口号一起构造成一个DatagramPacket类型的对象,这样数据的准备就完成了,发送时调用网络连接对象中的send方法发送该对象即可。

 String s = “Hello”;

                   String host = “127.0.0.1”;

                   int port = 10001;

                  //将发送的内容转换为byte数组

                   byte[] b = s.getBytes();

                   //将服务器IP转换为InetAddress对象

                   InetAddress server = InetAddress.getByName(host);

                   //构造发送的数据包对象

                   DatagramPacket sendDp = new DatagramPacket(b,b.length,server,port);

                   //发送数据

                   ds.send(sendDp);

UDP方式也遵循“请求-响应”模型.
<3>接收数据
首先构造一个数据缓冲数组,该数组用于存储接收的服务器端反馈数据,该数组的长度必须大于或等于服务器端反馈的实际有效数据的长度。然后以该缓冲数组为基础构造一个DatagramPacket数据包对象,最后调用连接对象的receive方法接收数据即可。接收到的服务器端反馈数据存储在DatagramPacket类型的对象内部。
<4>关闭连接
关闭连接使用连接对象中的close方法即可,实现的代码如下:

                   ds.close();

UDP方式的同一个网络连接对象,可以发送到达不同服务器端IP或端口的数据包,这点是TCP方式无法做到的。

UDP方式服务器端网络编程:
<1>服务器端监听某个端口

DatagramSocket ds = new DatagramSocket(10010);

<2>接收客户端发送过来的数据
<3>逻辑处理
<4>将处理以后的结果再发送给客户端
服务器端需要获得客户端的IP和客户端使用的端口号,这个都可以从接收到的数据包中获得。

 //获得客户端的IP

     InetAddress clientIP = receiveDp.getAddress();

         //获得客户端的端口号

         Int clientPort = receiveDp.getPort();

<5>关闭服务器端连接

 ds.close();

网络协议

·网络协议是指对于网络中传输的数据格式的规定。网络协议的实质是客户端程序和服务器端程序对于数据的一种约定.在进行设计时一般遵循“简单、通用、容易解析”的原则进行。
·一般都会涉及到两个网络协议格式:客户端发送数据格式和服务器端反馈数据格式

客户端程序需要完成的处理为:

1、 客户端发送协议格式的生成
2、 服务器端反馈数据格式的解析
服务器端程序需要完成的处理为:
1、 服务器端反馈协议格式的生成
2、 客户端发送协议格式的解析

·由于各种网络程序使用不同的协议格式,所以不同网络程序的客户端之间无法通用。

网络编程示例

质数判别示例

1、 客户端程序功能:
a)         接收用户控制台输入
b)         判断输入内容是否合法
c)         按照协议格式生成发送数据
d)         发送数据
e)         接收服务器端反馈
f)          解析服务器端反馈信息,并输出
2、 服务器端程序功能:
a)         接收客户端发送数据
b)         按照协议格式解析数据
c)         判断数字是否是质数
d)         根据判断结果,生成协议数据
e)         将数据反馈给客户端

猜数字小游戏

 客户端程序功能列表:

1、 接收用户控制台输入
2、 判断输入内容是否合法
3、 按照协议格式发送数据
4、 根据服务器端的反馈给出相应提示
         服务器端程序功能列表:

1、 接收客户端发送数据
2、 按照协议格式解析数据
3、 判断发送过来的数字和随机数字的关系
4、 根据判断结果生产协议数据
5、 将生产的数据反馈给客户端

心得体会

本周通过这篇长博客的学习,让我对网络编程有了一定的了解。虽然博客很长,但还是耐心仔细地读完了,其中作者把不易懂的知识通过举身边的例子展现出来,这种方式非常好,可以使我们这种刚入门的学生快速理解。看了这篇博客对于本周的实验也是相当有帮助的,使我和小伙伴之间的合作更加顺利。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 100/100 1/2 10/15
第二周 100/200 2/4 15/30
第三周 300/500 1/5 30/60
第四周 300/800 1/6 30/90
第五周 347/1147 1/7 30/120
第六周 352/1499 2/9 30/150
第七周 258/1757 2/11 30/180
第八周 350/2107 2/13 30/210
第九周 550/2657 2/15 30/240
第十周 546/3203 2/17 30/270

参考资料

原文地址:https://www.cnblogs.com/ZouJR/p/5468069.html