java学习(18)
1.网络编程&& Udp这篇来写关于网络编程的内容。
1.1 网络通信介绍
(1)tcp/ip协议
(2)udp/ip协议
1.2 Socket通信
网络编程三要素:
(1)ip:一个计算的标示(找到这个计算机)
(2)端口:应用程序都会对应一个端口,用来进行通信,有效端口:0~65535,其中0~1024系统使用或保留端口(360查看端口)。
(3)协议:总共有2种协议:TCP、UDP
1.3 三要素详解:
(1)特殊的IP地址:
127.0.0.1本地回环地址用来做一些本地测试
pingIP地址:用来检测本机是否可以和指定的IP地址的计算机可以进行正常通讯
ipconfig:用来查看IP地址
xxx.xxx.xxx.255 :广播地址
(2)端口号
物理端口:物理设备对应的端口、网卡口
逻辑端口:用来标示我们的计算机上的进程 , 端口号的有效范围应该是 0-65535,其中0-1024被系统占用或者保留
(3)协议:
UDP协议:
A.把数据打成一个数据包 , 不需要建立连接
B.数据包的大小有限制不能超过64k
C.因为无连接,所以属于不可靠协议(可能丢失数据)
D.因为无连接 ,所以效率高
TCP协议:
A.需要建立连接,形成连接通道
B.数据可以使用连接通道直接进行传输,无大小限制
C.因为有链接,所以属于可靠协议
D.因为有链接,所以效率低
1.4 InetAddress:IP地址的描述类
A:InetAddress类的概述
为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress 供我们使用此类表示互联网协议 (IP) 地址。
B:InetAddress类的常见功能
public static InetAddress getByName(String host)( host: 可以是主机名,也可以是IP地址的字符串表现形式)
public String getHostAddress()返回 IP 地址字符串(以文本表现形式)。
public String getHostName()获取此 IP 地址的主机名。
示例:
public static void main(String[] args) throws Exception { InetAddress address = InetAddress.getByName("10.100.9.174"); System.out.println(address.getHostAddress()); System.out.println(address.getHostName()); }
1.5 socket编程(套接字编程,网络编程)
Socket套接字:网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
Socket原理机制:
(1)通信的两端都有Socket。
(2)网络通信其实就是Socket间的通信。
(3)数据在两个Socket间通过IO传输。
1.6 UDP协议
特点:
(1)把数据打包
(2)不需要建立连接,也称为面向无连接协议
(3)数据需打包,数据大小有限制64k
(4)无需建立连接,所以不可靠
(5)速度快
UDP通信步骤:
发送端步骤:
UDP发送数据的步骤:
A:创建UDP发送数据端Socket对象
B:创建数据包,并给出数据,把数据打包
C:通过Socket对象发送数据包
D:释放资源
示例:
public static void main(String[] args) throws Exception { //1.创建发送端Socket对象 DatagramSocket ds = new DatagramSocket(); String str = "hello,world"; byte[] buf = str.getBytes(); int length = buf.length; InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 6666; //2.创建数据包 DatagramPacket dp = new DatagramPacket(buf,length,address,port); //3.发送数据 ds.send(dp); //4.释放资源 ds.close(); }
接收端步骤:
UDP协议接收数据步骤:
A:创建UDP接收数据端Socket对象
B:创建一个接收数据的数据包
C:接收数据,数据在数据包中
D:解析数据包,并把数据显示在控制台
E:释放资源
示例:
运行:public static void main(String[] args) throws Exception { //1.创建接收端socket对象 DatagramSocket ds = new DatagramSocket(6666); //2.创建数据包 byte[] buf = new byte[1024]; int length = buf.length; DatagramPacket dp = new DatagramPacket(buf, length); //3.接受数据 ds.receive(dp); byte[] data = dp.getData(); int len = dp.getLength(); System.out.println(new String(data, 0, len)); //4.释放资源 ds.close(); }
1.7案例:键盘录入数据实现数据的动态发送
发送端:
接收端:public class UdpClient { public static void main(String[] args) throws Exception { //创建发送端socket对象 DatagramSocket ds = new DatagramSocket(); InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 7777; Scanner sc = new Scanner(System.in); String line; System.out.println("请输入聊天内容:"); while((line = sc.nextLine())!=null){ System.out.println("请输入聊天内容:"); byte[] buf = line.getBytes(); int length = buf.length; DatagramPacket dp = new DatagramPacket(buf, length, address, port); //发送信息 ds.send(dp); } //释放资源 ds.close(); } }
运行:public class UdpServer { public static void main(String[] args) throws Exception { //创建接收端socket对象 DatagramSocket ds = new DatagramSocket(7777); while(true){ byte[] buf = new byte[1024]; int length = buf.length; DatagramPacket dp = new DatagramPacket(buf, length); ds.receive(dp); byte[] data = dp.getData(); int len = dp.getLength(); System.out.println("客户端:"+new String(data,0,len)); } } }
2.TCP协
2.1 TCP协议
特点:
1.需要建立通道
2.传送大量数据无限制
3.面向连接
4.可靠
5.速度慢
TCp协议书写步骤:
发送端:
TCP协议发送数据步骤:
A:创建TCP协议发送端Socket对象
指定服务器IP及端口
B:获取输出流,并写数据
C:释放资源
示例:
public static void main(String[] args) throws Exception { //创建socket对象 Socket socket = new Socket("127.0.0.1",20000); //获取输出流 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //获取键盘输入 System.out.println("请输入聊天内容:"); Scanner sc = new Scanner(System.in); String line = sc.nextLine(); //写到流中 bw.write(line); bw.flush(); //释放资源 socket.close(); }
注意:TCP协议是不能直接运行客户端的,必须先运行服务器。因为他是一种可靠的协议。直接运行客户端会报错:
接收端:
TCP协议接收数据步骤:
A:创建TCP协议接收端Socket对象
B:监听客户端连接
C:获取输入流,并读取数据,显示在控制台
D:释放资源
示例:
public static void main(String[] args) throws Exception { //创建socket对象 ServerSocket serverSocket = new ServerSocket(20000); //监听 Socket socket = serverSocket.accept(); //获取通道输入流 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //读数据 String line = br.readLine(); System.out.println("客户端:"+line); //释放资源 socket.close(); }
2.2 案例:客户端键盘录入数据,服务器端接收数据在控制台输出
上述Tcp代码运行即可:
2.3 案例:上传文本文件
客户端:
a: 读取文本文件中的数据
b: 发送到服务器端
服务器:
a: 读取流通道中的数据
b: 把数据写入到文本文件中
分析:基于Tcp协议的文本文件上传
发送端:
接收端:public class TcpClient { public static void main(String[] args) throws Exception { //创建socket对象 Socket socket = new Socket("127.0.0.1",20000); //封装流 BufferedReader br = new BufferedReader(new FileReader("a.txt")); String readLine; //获取输出流 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); while(( readLine = br.readLine())!=null){ //写到流中 bw.write(readLine); bw.newLine(); bw.flush(); } //释放资源 socket.close(); } }
public class TcpServer { public static void main(String[] args) throws Exception { //创建socket对象 ServerSocket serverSocket = new ServerSocket(20000); //监听 Socket socket = serverSocket.accept(); String line; //获取通道输入流 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //写到文件 b.txt 中 BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); while((line = br.readLine())!=null){ bw.write(line); bw.newLine(); bw.flush(); } //释放资源 socket.close(); } }
2.4 基于多线程实现文本文件的上传
分析:对于上述代码,由于接收端把写入文件写死了,只能有一个发送端上传文件,并且每次都会把文件内容覆盖掉,因此,利用多线程改进,可以支持多个发送端上传文件,并且可以使用UUID类每次生成一个随机文件名,避免内容覆盖
改进:
发送端代码不用调整,改进接收端代码,以及添加一个线程类和利用UUID类来产生文件名字的类:
接收端:
线程类:public class TcpServer { public static void main(String[] args) throws Exception { //创建socket对象 ServerSocket serverSocket = new ServerSocket(20000); while(true){ //监听 Socket socket = serverSocket.accept(); new Thread(new ServerThread(socket)).start(); } } }
产生文件名类:public class ServerThread implements Runnable{ Socket socket; public ServerThread(Socket socket){ this.socket = socket; } @Override public void run() { try { String line; //获取通道输入流 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedWriter bw = new BufferedWriter(new FileWriter(UUIDUtils.getFiledName())); while((line = br.readLine())!=null){ bw.write(line); bw.newLine(); bw.flush(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
这样,每次复制得到的文件名不同:public class UUIDUtils { public static String getFiledName(){ String fileName = UUID.randomUUID().toString(); fileName = fileName.replace("-", "")+".txt"; return fileName; } }
2.5 软件当中基本都是udp和tcp混用