黑马程序员——Java基础——网络编程未完待续
第一讲 网络编程概述
1、网络传输模型:OSI参考模型和TCP/IP参考模型
开发出一传输层和网际层,应用层为:FTP和HTTP协议;传输层:UDP和TCP;网际层为:IP
用户在应用层操作数据传输的过程就是,线程层层封包,经过物理层传输后,层层拆包的过程:
2、网络通信的三要素:IP地址,端口号,传输协议
2.1 IP地址:
×每个网络终端都有的一个独立的地址,传输数据的标志
以下是实例获得IP地址的方法:(主机名:localhost)
1 // ip包括 主机名/IP地址 2 InetAddress ip=InetAddress.getLocalHost();//获得本机的IP 3 System.out.println(ip.toString());//加不加toString都一样 4 System.out.println(ip.getHostAddress());//得到IP地址 5 System.out.println(ip.getHostName());//得到主机名 6 // 获得任意一条IP地址:getByName 7 InetAddress ia=InetAddress.getByName("www.baodu.com");//可以直接写主机名或IP地址 8 System.out.println(ia.getHostAddress());//得到IP地址 9 System.out.println(ia.getHostName());//得到主机名 10 // 由于一个主机名对应多个地址;所有返回的IP对象不唯一 11 InetAddress[] iall=InetAddress.getAllByName("www.baodu.com");//得到IP地址数组集合 12
1 // 遍历 2 for(InetAddress b:iall){ 3 String badress=b.getHostAddress(); 4 String bname=b.getHostName(); 5 } 6
2.2 端口
×每个程序在设备上的唯一标识
端口范围:0~65535,尽量使用1024以上的没有被系统软件使用的端口
2.3传输协议UDP和TCP
网络协议:为计算机网络中进行数据交换而建立的规则,标准或约定的集合;
UDP:将数据和源和目的封装成包中,不需要连接;
每个数据包的代谢哦限制在64K
因为是无连接,是不可靠的协议
不需要建立连接,所以快:运用在qq视频等不怕数据丢失的
TCP:建立连接,新村传输的数据的通道
在连接中进行大数据量传输
通过3此握手完成连接,是可靠的协议
必须建立连接,效率低:运用在:迅雷等不能丢失数据的方式;
3.Socket:就是为网络服务提供的一种机制:
1)通信的两端都有Socket;
2)网络通信其实就是Socket间的通信;
3)数据在两个Socket间通过IO流传输;
4)Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port
UDP协议实例
1 /*通过UDP传输方式将一定文字信息发送 2 * 思路: 3 * 1.建立updsocket副,建立端点 4 * 2.提过数据,并将数据分割在到数据包中 5 * 3.通过Socket服务的发送功能,将数据包发送出去 6 * 4.关闭资源 7 */ 8 class SocketDemo { 9 public static void main(String[] args) throws IOException{ 10 // 1.创建UDP服务 11 DatagramSocket ds=new DatagramSocket(); 12 13 // 2.确定数据,封装成数据包 14 byte[] data="水音大美女".getBytes(); 15 // 3发送数据,数据包上写上要发生的地址,Socket只起到一个邮局作用 16 DatagramPacket dp=new DatagramPacket(data, data.length, InetAddress.getByName("192.168.5.159"),8888); 17 // 发送出去。邮局具有发送的方法 18 ds.send(dp); 19 // 关闭资源 20 ds.close(); 21 } 22 } 23 24 /*定义一个接受并处理数据的UDP端口 25 * 26 * 思路:1。定义UPDSocket的服务 27 * 2.定义一个数据包,存储接受到的字节数据 28 * 3.通过Socket服务的receive方法将收到的数据存入已定义好的数据包 29 * 4、通过数据包中的特定功能,将这些不同的数据取出,打印 30 * 5、关资源 31 */ 32 class UDPrece{ 33 public static void main(String[] args)throws Exception{ 34 // 1.创建UDPSocket 35 DatagramSocket ds=new DatagramSocket(8888); 36 while(true){ 37 // 2.定义数据包存储 38 byte[] buf=new byte[1024]; 39 DatagramPacket dp=new DatagramPacket(buf, buf.length); 40 // 通过服务的邮局的receive方法收数据 41 ds.receive(dp); 42 43 // 从数据包中获取数据 44 String ip=dp.getAddress().getHostAddress(); 45 // 注意只需要指定部分的数据即可 46 String data=new String(dp.getData(),0,dp.getLength()); 47 // 端口 48 int pot =dp.getPort(); 49 50 System.out.println(ip+":"+data+":"+pot); 51 } 52 // ds.close(); 53 } 54 }
实例练习
1 *键盘录入方式发送数据 2 */ 3 import java.net.*; 4 import java.io.*; 5 6 class Send { 7 public static void main(String[] args)throws Exception{ 8 DatagramSocket ds=new DatagramSocket(); 9 // 创建数据包,读取流 10 DatagramPacket dp=null; 11 BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in)); 12 String line=null; 13 while((line=bufr.readLine())!=null){ 14 // 将读取的line放在数据包里 15 byte[] buf=line.getBytes(); 16 dp=new DatagramPacket(buf, buf.length,InetAddress.getByName("192.168.5.159"),8888); 17 // 发送数据 18 ds.send(dp); 19 if("over".equals(line)){ 20 break; 21 } 22 } 23 ds.close(); 24 bufr.close(); 25 26 } 27 } 28 class Receive{ 29 public static void main(String [] args)throws Exception{ 30 DatagramSocket ds=new DatagramSocket(8888); 31 while(true){ 32 // 定义数据包计算用 33 byte[] buf=new byte[1024]; 34 DatagramPacket dp=new DatagramPacket(buf, buf.length); 35 ds.receive(dp); 36 // 获得数据 37 String ip=dp.getAddress().getHostAddress(); 38 String data=new String(dp.getData(),0,dp.getLength()); 39 int port=dp.getPort(); 40 System.out.println(ip+":"+data+":"+port); 41 } 42 // ds.close(); 43 } 44 }
实例3:编写聊天软件
1 /*编写聊天软件 2 * 有接受和发送部分 3 * 需要同时进行,所有需要多线程技术(一个接受,一个发送) 4 * 5 * 因为发送和接受不一致,所以定义连个run方法 6 * 两个要在不同的类中 7 */ 8 import java.net.*; 9 import java.io.*; 10 class Sendd implements Runnable{ 11 private DatagramSocket ds; 12 Sendd(DatagramSocket ds){ 13 this.ds=ds; 14 } 15 @Override 16 public void run() { 17 try { 18 // 创建数据包和键盘录入 19 DatagramPacket dp=null; 20 BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in)); 21 String line=null; 22 while((line=bufr.readLine())!=null){ 23 byte[] buf=line.getBytes(); 24 dp=new DatagramPacket(buf, buf.length,InetAddress.getByName("192.168.5.159"),8888); 25 26 ds.send(dp); 27 if(line.equals("886")) 28 break; 29 } 30 ds.close(); 31 } catch (Exception e) { 32 // TODO: handle exception 33 throw new RuntimeException("发送失败"); 34 } 35 } 36 } 37 38 39 class Receive implements Runnable{ 40 private DatagramSocket ds; 41 Receive(DatagramSocket ds){ 42 this.ds=ds; 43 } 44 45 public void run() { 46 try { 47 while(true){ 48 byte[] buf=new byte[1024]; 49 DatagramPacket dp=new DatagramPacket(buf, buf.length); 50 ds.receive(dp); 51 // 取出 52 String ip=dp.getAddress().getHostAddress(); 53 String data=new String(dp.getData(),0,dp.getLength()); 54 int port=dp.getPort(); 55 56 System.out.println(ip+":"+data+":"+port); 57 } 58 } catch (Exception e) { 59 throw new RuntimeException("接收失败"); 60 } 61 } 62 } 63 64 65 class Amin{ 66 public static void main(String[] args) throws Exception{ 67 new Thread(new Sendd(new DatagramSocket())).start(); 68 new Thread(new Receive(new DatagramSocket(8888))).start(); 69 } 70 }
TCP协议
TCP协议分客户端和服务端
1.客户端:
*创建Socket连接服务端(指定IP地址,端口号)通过ip地址找对应的服务器
*调用geInputStream()和getOutputStream()方法获取巨额服务的相连的IO流
*输入流可以读取服务的输出流写出的数据
*输出流可以写出数据到服务daunting的输入流
2.服务端:
×船舰ServerSocket(需要指定的端口号)
×调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
×调用Socket的getInputStream()和getOutputStream()方法获得和客户端相连的IO流
×输入流可以读取客户端输出流写出的数据
×输出流i可以写出数据到客户端的输如流;
1 /*需求:客户端向服务端发送数据,服务的接受后,给客户端反馈一下 2 * 3 */ 4 import java.net.*; 5 import java.io.*; 6 //客户端 7 class TcpClient{ 8 public static void main(String[] args)throws Exception{ 9 Socket s=new Socket("192.168.5.159",8888);//这个等于是邮局就知道发送的地点 10 // 向流中希尔数据,通过Socket发出去 11 OutputStream out=s.getOutputStream(); 12 out.write("大萌妹子".getBytes()); 13 // 获取流中的数据,也是通过邮局Socket 14 InputStream in=s.getInputStream(); 15 // 读取数据咯 16 byte[] b=new byte[1024]; 17 int len=in.read(b); 18 19 System.out.println(new String(b,0,len)); 20 21 s.close(); 22 } 23 } 24 25 //服务端 26 class TcpServer{ 27 public static void main(String[] args)throws Exception{ 28 ServerSocket ss=new ServerSocket(8888);//直接自己搞一个端口 29 Socket s=ss.accept();//使用服务端口获得的东西获得的客户端对象 30 // 获取一下客户端信息 31 String ip=s.getInetAddress().getHostAddress(); 32 System.out.println(ip+"connected~~~"); 33 // 获取流中信息 34 InputStream in=s.getInputStream(); 35 // 可以读流了 36 byte[] b=new byte[1024]; 37 int len=in.read(b); 38 System.out.println(new String(b,0,len)); 39 // 给流中写一点数据呗 40 OutputStream out=s.getOutputStream(); 41 out.write("收到鸟".getBytes()); 42 s.close(); 43 ss.close(); 44 } 45 }
实例2
1 /* 2 需求:建议一个文本转换器 3 客户给服务的发送文本,服务端会将文本转换成大写再犯客户 4 客户按over时,结束 5 练习的难点: 6 现象:客户端和服务端在莫名的等待 7 原因:因为都有阻塞式的方法,就是没有换行与刷新的步骤 8 解决:需要用到熟悉和唤醒的方式将希尔和读取的数据从流中刷新到内存中(newLine 和flush) 9 使用PrintWriter能直接换行和刷新 10 */ 11 import java.net.*; 12 import java.io.*; 13 //客户端 14 class TcpClient{ 15 public static void main(String[] args)throws Exception{ 16 Socket s=new Socket("192.168.5.159",8888);//这个等于是邮局就知道发送的地点 17 //读取键盘的数据 18 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 19 // 用于输出数据用的流,与客户端相连发送用的 20 // BufferedWriter bout=new BufferedWriter(s.getOutputStream(),true); 21 PrintStream out=new PrintStream(s.getOutputStream(),true); 22 //用于接收客户端信息用的 23 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream())); 24 25 // 一下开把键盘信息发出去 26 String line=null; 27 while((line=br.readLine())!=null){ 28 if(line.equals("over")){ 29 break; 30 } 31 // bout.write(line); 32 // bout.newLine(); 33 // bout.flush(); 34 out.print(line); 35 36 // 读取返回的信息 37 String data=in.readLine(); 38 System.out.println(data); 39 } 40 br.close(); 41 s.close(); 42 } 43 } 44 45 //服务端 46 class TcpServer{ 47 public static void main(String[] args)throws Exception{ 48 ServerSocket ss=new ServerSocket(8888);//直接自己搞一个端口 49 Socket s=ss.accept();//使用服务端口获得的东西获得的客户端对象 50 51 // Ip 52 System.out.println(s.getInetAddress().getHostAddress()+"connect~~"); 53 // 读取流中的信息 54 BufferedReader bin=new BufferedReader(new InputStreamReader(s.getInputStream())); 55 // 发送流 56 PrintWriter pout=new PrintWriter(s.getOutputStream(),true); 57 58 String line=null; 59 while((line=bin.readLine())!=null){ 60 System.out.println(line); 61 62 63 pout.println(line.toUpperCase());//将line大写后写入输出流 64 } 65 s.close(); 66 ss.close(); 67 } 68 }
未完待续~~~