Java网络编程
网络通信的要素
-
网络编程中的两个主要问题:
-
如何准确定位到网络上的一台或多台主机
-
找到主机后如何进行通信
-
-
网络编程中的要素:
-
IP和端口号
-
网络通信协议
-
IP
ip地址:InetAddress类
-
127.0.0.1:本机
-
ipconfig:查询本地ip
-
ip地址分类:
-
ipv4 / ipv6
-
ipv6:128位,8个无符号整数
-
-
公网(互联网) / 私网(局域网)
-
1 public static void main(String[] args) { 2 try { 3 //getByName返回查询的主机地址 4 InetAddress inetaddress1 = InetAddress.getByName("127.0.0.1"); 5 System.out.println(inetaddress1);// /127.0.0.1 6 InetAddress inetaddress2 = InetAddress.getByName("www.baidu.com"); 7 System.out.println(inetaddress2);// www.baidu.com/14.215.177.38 8 9 //getLocalHost返回本机名称+地址 10 InetAddress inetaddress3 = InetAddress.getLocalHost(); 11 System.out.println(inetaddress3);// Colins-LenovoR720/192.168.226.1 12 13 } catch (UnknownHostException e) { 14 e.printStackTrace(); 15 } 16 }
端口
端口表示计算机上一个程序的进程
-
不同的进程端口号不同
-
端口号:0-65535,
-
端口分为TCP端口和UDP端口,所以实际端口数量=65536*2,但单个协议下端口号不能冲突
-
端口分类:
-
公有端口:0-1023
-
http:80
-
https:443
-
ftp:21
-
Telent:23
-
-
程序注册端口:1024-49151
-
Tomcat:8080
-
MYSQL:3306
-
Oracle:1521
-
-
动态 / 私有端口:49152-65535
-
1 netstat -ano #cmd查看所有端口 2 netstat -ano|findstr "端口号" #查看指定端口 3 tasklist|findstr "端口号" #查看指定端口的进程
ip地址+端口:InetSocketAddress类
1 public static void main(String[] args) { 2 //创建InetSocketAddress对象,对象包含ip和端口号 3 InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",8080); 4 System.out.println(socketAddress);// /127.0.0.1:8080 5 }
通信协议
协议:约定
-
网络通信协议:TCP/IP协议簇
-
TCP:用户传输协议:面向连接,客户端-服务端,三次握手/四次握手,效率低
-
UDP:用户数据报:无连接,没有明确的客户/服务端界限,
-
IP:网络互连协议
-
TCP
实现客户端和服务端通信
客户端
-
连接服务器Socket
-
发送消息
服务器
-
建立服务器端口 ServerSocket
-
等待用户的连接 accept
-
接收用户消息
消息发送
1 //客户端 2 public class TcpClientDemo01 { 3 public static void main(String[] args) { 4 //提升作用域,以便在finally中关闭 5 Socket socket = null; 6 OutputStream os = null; 7 try { 8 //1.获取服务器的地址 9 InetAddress serverip = InetAddress.getByName("127.0.0.1"); 10 //2.获取端口号 11 int port = 9999; 12 //3.创建一个socket连接 13 socket = new Socket(serverip,port); 14 //4.发送消息 IO流 15 os = socket.getOutputStream(); 16 os.write("Hi!".getBytes()); 17 } catch (Exception e) { 18 e.printStackTrace(); 19 } finally { 20 //关闭资源 21 if (os != null) { 22 try { 23 os.close(); 24 } catch (IOException e) { 25 e.printStackTrace(); 26 } 27 } 28 if (socket != null) { 29 try { 30 socket.close(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 } 36 } 37 } 38 39 //服务端 40 public class TcpServerDemo01 { 41 public static void main(String[] args) { 42 //要实现在finally中关闭资源必须将作用域提升至try以外 43 ServerSocket serverSocket = null; 44 Socket socket = null; 45 InputStream is = null; 46 ByteArrayOutputStream baos = null; 47 try { 48 49 //1.ServerSocket创建服务器的地址---Socket->插座 50 serverSocket = new ServerSocket(9999); 51 52 while (true) { 53 //2.监听客户端连接(while true表示持续监听客户端) 54 socket = serverSocket.accept(); //阻塞式监听,会一直等待客户端连接 55 //3.读取客户端消息 56 is = socket.getInputStream(); 57 //管道流接收(通过管道连接服务器和客户端的输入输出) 58 baos = new ByteArrayOutputStream(); 59 byte[] buffer = new byte[1024]; 60 int len; 61 while ((len=is.read(buffer))!=-1){ 62 baos.write(buffer,0,len); 63 } 64 System.out.println(baos.toString()); 65 } 66 67 68 } catch (IOException e) { 69 e.printStackTrace(); 70 } finally { 71 //关闭资源 72 if (baos != null) { 73 try { 74 baos.close(); 75 } catch (IOException e) { 76 e.printStackTrace(); 77 } 78 } 79 if (is != null) { 80 try { 81 is.close(); 82 } catch (IOException e) { 83 e.printStackTrace(); 84 } 85 } 86 if (socket != null) { 87 try { 88 socket.close(); 89 } catch (IOException e) { 90 e.printStackTrace(); 91 } 92 } 93 if (serverSocket != null) { 94 try { 95 serverSocket.close(); 96 } catch (IOException e) { 97 e.printStackTrace(); 98 } 99 } 100 } 101 } 102 }
文件传输
Tomcat
服务器
-
Tomcat服务器
客户端
-
浏览器
启动Tomcat:bin目录 –> start.bat –> 浏览器访问localhost:8080
UDP
无连接,不需要知道对方的地址
没有明确区分服务器和客户机
消息发送
1 //UDP发送端 2 public class UdpClientDemo01 { 3 public static void main(String[] args) throws Exception { 4 //1.建立Socket 5 DatagramSocket socket = new DatagramSocket(); 6 //这里也可以作为服务器端接收,UDP没有明确的服务器和客户机 7 //DatagramSocket socket = new DatagramSocket(8080); 8 9 //2.建包 10 String msg = "Hi UDP"; 11 //建立发送对象 12 InetAddress localhost = InetAddress.getByName("localhost"); 13 int port = 9090; 14 //DatagramPacket(数据,数据起始位置,数据长度,数据接收方ip+端口) 15 DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port); 16 17 //3.发送包 18 socket.send(packet); 19 20 //4.关闭流 21 socket.close(); 22 } 23 } 24 25 //UDP接收端 26 public class UdpServerDemo01 { 27 public static void main(String[] args) throws Exception{ 28 //1.开放端口 29 DatagramSocket socket = new DatagramSocket(9090); 30 31 //2.接收数据包 32 byte[] buffer = new byte[1024]; 33 DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); 34 //阻塞接收 35 socket.receive(packet); 36 System.out.println(packet.getAddress().getHostAddress());//输出客户端地址 37 //System.out.println(packet.getData()); 38 System.out.println(new String(packet.getData(),0,packet.getLength())); 39 //3.关闭流 40 socket.close(); 41 } 42 }
聊天
1 public class UdpSenderDemo01 { 2 public static void main(String[] args) throws Exception{ 3 DatagramSocket socket = new DatagramSocket(8888); 4 5 //准备数据,控制台读取 System.in 6 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 7 8 while (true){ 9 String data = reader.readLine(); 10 byte[] datas = data.getBytes(); 11 DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666)); 12 socket.send(packet); 13 if (data.equals("close")){ 14 break; 15 } 16 } 17 socket.close(); 18 } 19 } 20 21 22 public class UdpReceiverDemo01 { 23 public static void main(String[] args) throws Exception{ 24 DatagramSocket socket = new DatagramSocket(6666); 25 26 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 27 28 while (true){ 29 //准备接收包裹 30 byte[] container = new byte[1024]; 31 DatagramPacket packet = new DatagramPacket(container, 0, container.length); 32 socket.receive(packet); //阻塞式接收包裹 33 34 //读出接收的数据,设置连接断开条件 35 byte[] data = packet.getData(); 36 // String receiveData = new String(data, 0, data.length); 37 String receiveData = new String(data, 0, packet.getLength()); 38 System.out.println(receiveData); 39 if (receiveData.trim().equals("close")){ 40 break; //这里无法退出?以上receiveData用原本的方法会在结尾带有很多空格 41 } //改为trim或packet.getlength()即可正常退出 42 } 43 socket.close(); 44 } 45 }