------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、网络通讯
概念:网络间数据的传输、交互。
三要素:IP地址、端口号、传输协议。
——>IP地址
1、网络中设备的标识
2、单纯的IP地址不易记忆,可用主机名替代。
3、如果本机上没有配置任何IP地址的情况下,本机默认的IP地址为127.0.0.1
本地回环地址:127.0.0.1 主机名:localhost
用处:检验本机网卡是否运行正常等。
——>端口号
概念:用于标识进程的数字称为进程的逻辑地址,简称端口号。它是不同进程的标识。有效端口:0~65535,其中0~1024系统使用或保留端口。
——>传输协议
概念:是数据在网络传输中需要遵守的各种规则。
TCP/IP协议:TCP/IP协议是国际组织通用的传输协议,几乎所有类型的操作系统(OS)都安装了这个协议。
二、网络模型
作用:研究网络通信中各个部件之间的通信规则,一般是指OSI七层参考模型和TCP/IP四层参考模型。
模型示意图:
数据传输过程:数据从网络的一端从上倒下经过层层封装后,发送到网络另一端从下到上通过层层解封最终在应用层完成数据交互。
OSI参考模型: 应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。
TCP/IP参考模型: 应用层、传输层、网际层、主机至网络层。
各层主要协议:
1、应用层
HTTP协议:超文本传输协议(Hyper Text Transmission Protocol)
FTP协议:文件传输协议(File Transmission Protocol)
2、传输层
UDP协议:用户数据报协议(User Datagram Protocol)
TCP协议:传输控制协议(Transmission Controllable Protocol)
3、网络层
IP地址协议:互联网协议(Internet Protocol)
其中的UDP和TCP是我们网络编程用到的两个主要协议。
两个协议的比较:
1、UDP协议:是面向无连接,明确了对方的端口,无论在不在网上,只管传输,不在就会丢失数据。只求速度,应用于网络视频会议和聊天等应用程序中。
特点是:
(1)将数据和源、目的封装成包,不需要建立链接;
(2)每个数据包的大小限制在64K之内;
(3)因无连接,是不可靠的协议;
(4)不需建立连接,速度快;
2、TCP协议:是面向连接的,必须连接成功才能传输数据,应用于下载等程序上。
特点是:
(1)建立连接,形成传输数据通道;
(2)在连接中进行大数据量传输;
(3)通过三次握手完成连接,是可靠的协议;
(4)必须建立连接,效率会低一些;
网络三要素在Java中的体现:
1、IP地址在Java中的体现
InetAddress类表示的是对网络通讯的IP地址的封装。
getHostName():获取此 IP 地址的主机名。
getHostAddress():返回 IP 地址字符串(以文本表现形式)。
getLocalHost():返回本地主机。
getByAddress(byte[] addr):在给定原始 IP 地址的情况下,返回 InetAddress 对象。
getByAddress(String host, byte[] addr):根据提供的主机名和 IP 地址创建 InetAddress。
getByName(String host):在给定主机名的情况下确定主机的 IP 地址。
getAllByName(String host):在给定主机名的情况下,根据系统上配置的名称服务返回其 IP 地址所组成的数组。
2、端口在Java中的体现
由于端口仅仅是数字标识,所以没有必要将端口封装成对象。
3、传输协议在Java中的体现
Java将传输层常见的协议TCP和UDP分别封装成了TCP相关类和UDP相关类。
UDP协议相关的类:
——>DatagramSocket类
对UDP协议传输数据需要的Socket通信端点进行了封装。此类表示的通信端点Socket用于发送和接收UDP数据传输过程中的数据报包。DatagramSocket既可以用于发送数据,又可以用于接收数据。
1、DatagramSocket和DatagramPacket构造方法中IP和Port参数的关系
DatagramPacket类在构造方法中涉及到的IP地址和端口号指的是Socket通信端点将数据报包发送到的目的地所在主机的IP地址和端口号;
DatagramSocket类在构造方法中涉及到的IP地址和端口号指的是Socket通信端点本身所在主机的IP地址和端口号;
DatagramSocket构造中指定的是数据的源,DatagramPacket构造中指定的是数据的目的地;
DatagramSocket仅仅负责数据的发送和接收,而对数据的封装工作全部由DatagramPacket类进行了封装。
2、构造方法摘要
DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口。
DatagramSocket(int port):创建数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket(int port, InetAddress laddr):创建数据报套接字,将其绑定到指定的本地地址。
3、方法摘要
close():关闭此数据报套接字。
send(DatagramPacket p):从此套接字发送数据报包。
receive(DatagramPacket p):从此套接字接收数据报包。
注意:receive方法是一个阻塞式方法。程序中如果调用了这个方法,并且对应的接收端的Socket端点没有接收到数据报包,就会一直等待不动。直到这个接收端的DatagramSocket接收到了数据报包,receive方法才会被执行完。这样整个程序就向下继续执行。
——>DatagramPacket类
此类是对UDP数据传输过程中的数据报包的封装。被final修饰,不可以被继承.构造方法中涉及到的IP地址和端口号指的是数据报包被发送的目的地所在主机的IP地址和端口号。DatagramPacket是一个JavaBean类,它的方法主要分成了对私有字段的Set和Get方法.
构造方法摘要
用于UDP数据传输中的用于接收数据的数据报包对象
DatagramPacket(byte[] buf,int length);
DatagramPacket(byte[] buf,int offset,int length);
用于UDP数据传输中的用于发送数据的数据报包对象
DatagramPacket(byte[] buf,int length,InetAddress address,int port);
DatagramPacket(byte[] buf,int offset,int length,InetAddress address,int port);
TCP协议相关类:
——>Socket类
两台主机间通信的端点(称客户端Socket端点或者Socket端点),实现了客户端的套接字。
(1)构造方法摘要
Socket():通过系统默认类型的 SocketImpl 创建未连接套接字。
Socket(String host, int port):创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket(InetAddress address, int port):创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
(2)Socket类负责通信的方法
getInputStream():获取网络输入流,用于通信双方的“接收”。作用:可以通过这个输入流从Socket读取字节数据byte[]。
getOutputStream():获取网络输出流,用于通信双方的“发送”。作用:可以通过这个输出流向Socket写入字节数据byte[]。
shutdownInput():关闭客户端的Socket输入流。
shutdownOutput():关闭客户端的Socket输出流 。
——>ServerSocket类
这个类实现了服务器端的Socket通信端点。这个服务器端的Socket端点等待来自网络中的其他客户端Socket端点的请求。
(1)构造方法摘要
ServerSocket():创建非绑定服务器套接字。
ServerSocket(int port):创建绑定到特定端口的服务器套接字。
(2)Socket类负责通信的方法
accept():监听要连接到这个ServerSocket服务端的连接并接受这个连接。连接完成之后返回连接客户端的Socket副本。
getInetAddress():获取ServerSocket所在本机的IP地址
getLocalPort():获取ServerSocket所监听的本机的进行网络通讯的App的端口号
注意:accept()方法是一个阻塞式方法,这个方法会一直阻塞直到有来自客户端的Socket和这个ServerSocket之间的连接被创建。
三、网络编程
网络编程其实就是Socket编程。而Socket是为网络服务提供的一种机制,每个应用程序都有一个类似网卡的插槽,两台机器中的软件通信,每个软件都相当于Socket。Socket通信端点具备了,但是数据传输协议是不一样的。因此每一种数据传输协议都有自己特有创建Socket通信端点的方法。
——>基于UDP
发送端:
1、建立UDP的Socket服务。
2、将要发送的数据封装到数据包中。
3、用UDP的socket服务将数据包发送出去。
4、关闭Socket服务。
代码模版:
1 DatagramSocket ds = new DatagramSocket(); 2 byte[] b = "haha".getBytes(); 3 DatagramPacket dp = newv DatagramPacket(b,0,b.length,InetAddress.getByName("127.0.0.1"),8888); 4 ds.send(dp); 5 ds.close();
接收端:
1、 建立UDP Socket服务,因为要接收数据,必须要明确一个端口号。
2、定义一个数据包,用来存储接收到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3、通过socket服务的receive方法,将接收到的数据存入已定义好的数据包中。
4、通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。
5、关闭Socket服务。
代码模版:
1 DatagramSocket ds = new DatagramSocket(8888); 2 byte[] b = new byte[1024]; 3 DatagramPacket dp = new DatagramPacket(b,b.length); 4 ds.receive(dp); 5 String str = new String(dp.getData(),0,dp.getLength()); 6 System.out.println(str+"--"+dp.getAddress()); 7 ds.close();
注意:发送端与接收端是两个独立的运行程序。在发送端,要在数据包对象中明确目的地IP及端口。在接收端,要指定监听的端口。
示例代码:
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; public class UDPClient { /* * udp客户端 */ public static void main(String[] args) throws IOException { //1、定义服务器地址、端口,要发送的数据 InetAddress address = InetAddress.getByName("localhost"); int port = 8800; byte[] b = "我是被发送的数据!".getBytes(); //2、创建packet DatagramPacket packet = new DatagramPacket(b,b.length,address,port); //3、创建socket DatagramSocket socket = new DatagramSocket(); //4、发送数据 socket.send(packet);//此方法接收导数据前,一直处于阻塞状态 System.out.println("数据已发送。"); /* * 接收服务器的回应 */ //创建数据报接收数据 byte[] b2 = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(b2,b2.length); //接收数据 socket.receive(packet2); //输出数据 String message2 = new String(b2,0,packet2.getLength()); System.out.println("服务器说:" + message2); //关闭资源 socket.close(); } } import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class UDPServer { /* * udp服务器 */ public static void main(String[] args) throws IOException { //1、创建datagramPacketSocket,指定端口号 DatagramSocket socket = new DatagramSocket(8800); //2、创建数据报,用来接收数据 byte[] b = new byte[1024]; DatagramPacket packet = new DatagramPacket(b,b.length); //3、接收数据 System.out.println("服务器已启动,等到接收数据。。。"); socket.receive(packet); //4、读取数据 String message = new String(b,0,packet.getLength()); System.out.println("接收到的数据为:"+ message); /* * 服务器对客户端做出回应 */ //获得客户端地址和端口,创建回应数据 InetAddress address = packet.getAddress(); int port = packet.getPort(); byte[] b2 = "欢迎你!".getBytes(); DatagramPacket packet2 = new DatagramPacket(b2,b2.length,address,port); //发送数据 socket.send(packet2); //关闭资源 socket.close(); } }
——>基于TCP
客户端:
1、创建Socket服务,明确要连接的主机端口。
2、为了发送数据,应获取Socket中的输出流。如果要接收服务端的反馈信息,还需要获取Socket的输入流。
3、通过输出流的write()方法,将要发送的数据写入到流中。
4、关闭Socket流资源。
代码模版:
1 Socket s = new Socket("192.168.0.1",8888); 2 OutputStream out = s.getOutputStream(); 3 out.write("haha".getBytes()); 4 s.close();
服务器端:
1、建立服务端的Socket服务,并监听一个端口。通过ServerSocet带端口参数的构造函数完成。
2、获取连接过来的客户端对象,通过ServerSocket的阻塞式方法accept()接收客户端对象。
3、客户端如果发过来数据,则服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过来的数据,并输出到指定目的地。
4、关闭资源。(关闭客户端,一般不关服务端)
代码模版:
1 ServerSocket ss = new ServerSocket(8888); 2 Socket s = ss.accept (); 3 InputStream in = s.getInputStream(); 4 byte[] buf = new byte[1024]; 5 int num = in.read(buf); 6 String str = new String(buf,0,num); 7 System.out.println(s.getInetAddress().toString()+":"+str); 8 s.close(); 9 ss.close();
示例代码:
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.io.OutputStream; 7 import java.io.PrintWriter; 8 import java.net.ServerSocket; 9 import java.net.Socket; 10 import java.nio.Buffer; 11 12 public class Server { 13 /* 14 * 服务器 15 */ 16 public static void main(String[] args) { 17 try { 18 //创建ServerSocket的对象,绑定端口8888 19 ServerSocket serverSocket = new ServerSocket(8888); 20 System.out.println("服务器即将启动,等待客户端的连接..."); 21 //监听客户端,创建Socket的对象 22 Socket socket = serverSocket.accept(); 23 //取得输入流 24 InputStream is = socket.getInputStream(); 25 //将字节流转化成字符流 26 InputStreamReader isr = new InputStreamReader(is); 27 //构建缓冲 28 BufferedReader bf = new BufferedReader(isr); 29 //定义oldStr存储客户端传送过来的字符串 30 String oldStr = null; 31 String newStr = null; 32 //如果读取内容不为空,将其赋值给oldStr 33 while((oldStr=bf.readLine()) != null){ 34 //反转字符串 35 newStr = reversal(oldStr); 36 System.out.println("服务器说:你给我发的字符串\""+ oldStr + "\",反转后已经发给你了!"); 37 } 38 socket.shutdownInput(); 39 //获取输出流 40 OutputStream os = socket.getOutputStream(); 41 //将字节流包装为打印流 42 PrintWriter wp = new PrintWriter(os); 43 //将反转后的字符串发送给客户端 44 wp.write(newStr); 45 wp.flush(); 46 socket.shutdownOutput(); 47 48 //关闭相关资源 49 wp.close(); 50 os.close(); 51 bf.close(); 52 isr.close(); 53 is.close(); 54 socket.close(); 55 serverSocket.close(); 56 57 } catch (IOException e) { 58 e.printStackTrace(); 59 } 60 } 61 62 //revesal()方法实现字符串的反转 63 public static String reversal(String str){ 64 String myStr =""; 65 //将字符串转化成字符数组 66 char[] charArr = str.toCharArray(); 67 for(int i=charArr.length-1; i>=0; i--){ 68 //从charArr尾部开始依次将单个字符和myStr连接 69 myStr = myStr + charArr[i]; 70 } 71 return myStr; 72 } 73 } 74 75 public class Client { 76 /* 77 * 客户端 78 */ 79 public static void main(String[] args) { 80 System.out.print("请输入待反转的字符串:"); 81 //从键盘获取输入的字符串 82 Scanner sc = new Scanner(System.in); 83 String oldStr = sc.next(); 84 try { 85 //创建的关于本机服务器的一个Socket对象,通讯端口8888 86 Socket socket = new Socket("localhost",8888); 87 //获取输出流 88 OutputStream os = socket.getOutputStream(); 89 //将输出流转化为打印流 90 PrintWriter pw = new PrintWriter(os); 91 //向服务器传送字符串 92 pw.write(oldStr); 93 System.out.println("客户端说:我已经把字符串\""+ oldStr +"\"发送给服务器了!"); 94 //刷新pw 95 pw.flush(); 96 socket.shutdownOutput(); 97 98 //获取输入流 99 InputStream is = socket.getInputStream(); 100 //转化成字符流 101 InputStreamReader isr = new InputStreamReader(is); 102 //构建缓冲区 103 BufferedReader br = new BufferedReader(isr); 104 String newStr = null; 105 while((newStr=br.readLine()) != null){ 106 System.out.println("客户端说:服务器已经把反转过的字符串发个给我了!"); 107 System.out.println("反转过后的字符串为:" + newStr); 108 } 109 socket.shutdownInput(); 110 111 //关闭相关资源 112 br.close(); 113 isr.close(); 114 is.close(); 115 pw.close(); 116 os.close(); 117 socket.close(); 118 119 } catch (UnknownHostException e) { 120 e.printStackTrace(); 121 } catch (IOException e) { 122 e.printStackTrace(); 123 } 124 } 125 126 }
TCP实现上传图片例子:
1 import java.io.*; 2 import java.net.*; 3 //客户端 4 class PicClient { 5 public static void main(String[] args) throws Exception{ 6 //对传入的值进行判断 7 if (args.length!=1) { 8 System.out.println("请指定一个图片文件!"); 9 return; 10 } 11 File file = new File(args[0]); 12 //对文件路径进行判断 13 if (!(file.exists()&&file.isFile())){ 14 System.out.println("你上传的文件有问题,非文件或者不存在!"); 15 return; 16 } 17 //判断是否是图片文件 18 if (!file.getName().endsWith(".jpg")){ 19 System.out.println("图片格式错误,请重新选择!"); 20 return; 21 } 22 //对文件大小进行判断 23 if (file.length()>1024*1024*5){ 24 System.out.println("你上传的文件过大!"); 25 return; 26 } 27 //创建服务 28 Socket s = new Socket("localhost",10000); 29 //读取图片数据 30 FileInputStream fis = new FileInputStream(file); 31 //用Socket服务输出流写入数据 32 OutputStream out = s.getOutputStream(); 33 BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); 34 byte[] buf = new byte[1024]; 35 int len = 0; 36 while ((len = fis.read(buf))! = -1){ 37 out.write(buf,0,len); 38 } 39 //结束标记,表示文件数据已经上传完了 40 s.shutdownOutput(); 41 String info=in.readLine();//读取返回信息 42 System.out.println(info); 43 fis.close();//关流 44 s.close(); 45 } 46 } 47 48 //服务端 49 class PicServer{ 50 public static void main(String[] args)throws Exception{ 51 //创建服务,监听端口 52 ServerSocket ss = new ServerSocket(10000); 53 while (true){ 54 //获取客户端对象 55 Socket s = ss.accept(); 56 //客户端执行线程 57 new Thread(new PicThread(s)).start(); 58 } 59 //ss.close(); 60 } 61 } 62 63 //利用多线程实现并发上传 64 class PicThread implements Runnable{ 65 private Socket s; 66 PicThread(Socket s){ 67 this.s = s; 68 } 69 public void run(){ 70 int count = 1; 71 //获取客户端ip 72 String ip = s.getInetAddress().getHostAddress(); 73 try{ 74 System.out.println(ip+" connected....."); 75 //通过客户端的读取流读取数据 76 InputStream in = s.getInputStream(); 77 //文件保存路径 78 File dir = new File("C:\\Users\\asus\\Desktop"); 79 //文件名 80 File file = new File(dir,ip+".jpg"); 81 //判断文件是否存在 82 while(file.exists()){ 83 file = new File(dir,ip+"("+(count++)+").jpg"); 84 } 85 //将数据写入到指定文件中 86 FileOutputStream fos = new FileOutputStream(file); 87 byte[] buf = new byte[1024]; 88 int len = 0; 89 while ((len = in.read(buf))! = -1){ 90 fos.write(buf,0,len); 91 } 92 //将收到图片数据的信息返回给客户端 93 OutputStream out = s.getOutputStream(); 94 out.write("上传成功!".getBytes()); 95 fos.close();//关流 96 s.close(); 97 }catch (Exception e){ 98 throw new RuntimeException(ip+"图片上传失败"); 99 } 100 } 101 }
四、URL
——>URL类
URL代表一个统一资源定位符,是对URL地址的封装,方便了我们对URL的操作。
1、构造方法摘要
URL(String spec):根据String表示形式创建URL对象。
URL(String protocol, String host, String file):根据指定的 protocol 名称、host 名称和file名称创建URL。
URL(String protocol, String host, int port, String file):根据指定protocol、host、port 号和file创建URL对象。
2、常用方法摘要
getProtocol():获取此URL的协议名称。
getHost():获取此URL的主机名(如果适用)。
getPath():获取此URL的路径部分。
getFile():获取此URL的文件名。
getQuery():获取此URL的查询部。
getPort():获取此URL的端口号。
openConnection():返回一个URLConnection对象,它表示到URL所引用的远程对象的连接。
——>URLConnection类
抽象类,它代表应用程序和URL之间的通信链接。此类的实例可用于读取和写入此URL引用的资源。
创建一个到URL的连接需要几个步骤:
(1)通过在URL上调用openConnection()方法创建连接对象。
(2)处理设置参数和一般请求属性。
(3)使用connect方法建立到远程对象的实际连接。
(4)远程对象变为可用。远程对象的头字段和内容变为可访问。
常用方法:
getInputStream():返回从此打开的连接读取的输入流。
getOutputStream():返回写入到此连接的输出流。
connect():打开到此URL引用的资源的通信链接(如果尚未建立这样的连接)。
五、网络架构
——>C/S
Client/Server 即客户端/服务端。
特点:
1、客户端和服务端都需要单独编写软件。
2、维护较麻烦。
好处:可以减轻服务端的压力,如网络游戏。
——>B/S
Browser/Server 即浏览器/服务端。
特点:
1、客户端不用单独编写软件。因为客户端用的就是浏览器。
2、对于软件升级,只要考虑服务端即可。
缺点:所有的程序都运行在服务端,客户端的浏览器毕竟解析能力较弱。