Java 网络编程
Posted shiyuan310
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 网络编程相关的知识,希望对你有一定的参考价值。
说道网络编程,了解socket编程,分为TCP和UPD,对于具体实现细节,就不知道。希望学完这一块,自己能够独立完成一个socket的编写。
关于互联网WEB相关的知识点,后面开始总结,今天不在此作介绍。
Socket套接字:网络上具有唯一标识的IP地址和端口组合在一起才能构成唯一能识别的标识符套接字。
Socket原理机制:
通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
Java中的网络支持:针对网络通信的不同层次,Java提供了不同的API,其提供的网络功能有四大类:
InetAddress:用于标识网络上的硬件资源,主要是IP地址
URL:统一资源定位符,通过URL可以直接读取或写入网络上的数据。
Sockets:使用TCP协议实现的网络通信Socket相关的类
Datagram:使用UPD协议,将数据保存在用户数据中,通过网络进行通信。
1:InetAddress
标识网络上的硬件资源,没有构造方法(默认都没有),标识互联网协议IP地址
1 package lesson1220Socket; 2 3 import java.net.InetAddress; 4 import java.net.UnknownHostException; 5 6 public class InetAddressDemo { 7 8 public static void main(String[] args) throws UnknownHostException { 9 InetAddress address = InetAddress.getLocalHost(); 10 11 //InetAddress ad = new InetAddress(); The constructor InetAddress() is not visible 12 13 byte [] by = address.getAddress(); //实际上里面存的值是[100, 98, 60, 87] 14 System.out.println(by); 15 System.out.println(address.getHostAddress()); 16 System.out.println(address.getHostName()); 17 return; 18 } 19 }
运行结果:
[B@626287d3
100.98.60.87
CN00204505
2、URL类
统一资源定位符,标识Internet上某一资源的地址,
Java中的网络编程
Java中的网路编程主要是Java的Socket编程,属于JavaEE中的高级的部分,以下内容是对java网路编程的一个小结,代码都是经过编译调试的
C/S程序应用:客户/服务器模式,如QQ客户端,客户端连到服务器上,一个C/S模式的应用必须有两套程序,一个是客户端的程序,一个是服务器程序。
B/S程序应用:浏览器/服务器模式,如当下的各种网站都是B/S模式,所有的程序代码都在服务器上,用户通过浏览器去访问。
C/S程序分为两种:
基于TCP协议:Socket(套接字), 可靠的编程: A->B 如打电话先建立连接
基于UDP协议:不可靠,如短信功能。
如果编写一个TCP程序需要JAVA的两个包支持:
java.net.*: 主要提供网络支持;
|-ServerSocket类:服务器端程序
|-Socket类:客户端程序
java,io.*:传递信息流
3、TCP编程
TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据。通过三次握手方式建立连接。形成传输数据的通道。在连接中进行大量数据的传输,效率会稍低。
Java中基于TCP协议实现网络通信的类:客户端是Socket, 服务器端是ServerSocket。
看上面图,可以看出Socket通信步骤:创建ServerSocket和Socket,打开连接到Socket的输入输出流,按照协议对Socket进行读写操作,关闭输入输出流,关闭Socket。
3.1 服务器端:
a:创建ServerScoket,并绑定端口
b:调用accept()开始监听端口
c:建立连接后,通过输入流获取客户端发送的请求信息
d:通过输出流向客户端返回响应信息
e:关闭Socket等相关资源
3.2 客户端:
a:创建Socket,并指定需要连接的服务器的IP和端口
b:建立连接后,通过输出流向服务器端发送信息
c:通过输入流获取服务器返回的响应信息
d:关闭Socket等资源
例子如下:
1 package lesson1220Socket; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.ServerSocket; 10 import java.net.Socket; 11 12 import com.sun.org.apache.xalan.internal.xsltc.trax.OutputSettings; 13 14 //基于TCP/IP协议的Socket,用户实现登录服务器端 15 public class ServeSocketDemo { 16 public static void main(String[] args) throws Exception { 17 18 //1、创建一个ServerSocket服务端,指定绑定的端口,并监听端口 19 ServerSocket ss = new ServerSocket(10086); //1024-65535的某个值 20 System.out.println("服务器端开始监听10086端口....."); 21 //2、调用accept方法开始监听端口 22 Socket socket = ss.accept(); 23 24 //3、获取输入流,并读取客户端信息 25 InputStream is = socket.getInputStream(); 26 InputStreamReader isr = new InputStreamReader(is); //InputStreamReader 27 BufferedReader br = new BufferedReader(isr); 28 29 String info = null; 30 while((info = br.readLine())!=null){ 31 System.out.println("我是服务器,客户端说:"+info); 32 } 33 socket.shutdownInput(); 34 35 //4、获取输出流,响应客户端请求 36 OutputStream os = socket.getOutputStream(); 37 PrintWriter pw = new PrintWriter(os); 38 pw.write("欢迎您"); 39 pw.flush(); 40 System.out.println("给客户端回响应....."); 41 42 //5、关闭资源 43 pw.close(); 44 os.close(); 45 br.close(); 46 isr.close(); 47 is.close(); 48 socket.close(); 49 ss.close(); 50 51 } 52 53 } 54 55 56 package lesson1220Socket; 57 58 import java.io.BufferedReader; 59 import java.io.IOException; 60 import java.io.InputStream; 61 import java.io.InputStreamReader; 62 import java.io.OutputStream; 63 import java.io.PrintWriter; 64 import java.net.Socket; 65 import java.net.UnknownHostException; 66 67 public class ClientSocketDemo { 68 69 public static void main(String[] args) throws UnknownHostException, IOException { 70 //1、创建客户端Socket,指定服务器和端口 71 Socket cs = new Socket("127.0.0.1", 10086); 72 System.out.println("与服务端建立连接....."); 73 74 //2、获取输出流,向服务器发送信息 75 OutputStream os = cs.getOutputStream();//直接输出流 76 PrintWriter pw = new PrintWriter(os); 77 pw.write("用户名:admin,密码:123"); 78 pw.flush(); 79 cs.shutdownOutput(); 80 System.out.println("向服务端发送信息....."); 81 82 //3、获取输入流,得到服务器响应信息 83 InputStream is = cs.getInputStream(); 84 InputStreamReader isr = new InputStreamReader(is); 85 BufferedReader br = new BufferedReader(isr); 86 String info; 87 while((info = br.readLine())!=null){ 88 System.out.println("我是客户端,服务端响应信息:"+info); 89 } 90 91 //4、关闭资源 92 br.close(); 93 isr.close(); 94 is.close(); 95 pw.close(); 96 os.close(); 97 cs.close(); 98 99 } 100 101 }
上面先运行服务端:ServeSocketDemo,再启动客户端:ClientSocketDemo
运行结果如下:
ServeSocketDemo:
服务器端开始监听10086端口.....
我是服务器,客户端说:用户名:admin,密码:123
给客户端回响应.....
ClientSocketDemo:
与服务端建立连接.....
向服务端发送信息.....
我是客户端,服务端响应信息:欢迎您
4、UDP编程
前面介绍的Socket编程都是基于TCP/IP协议的,现在来看一下基于UDP协议编程。
UPD协议(用户数据报协议)是无连接的、不可靠的、无序的,速度快。进行数据传输时,首先将要传输的数据定义成数据报(Datagram),大小限制在64k,在数据报中指明数据索要达到的Socket(主机地址和端口号),然后再将数据报发送出去。UDP协议的主要作用就是完成网络数据流和数据包之间的转换-------在信息发送端,UDP协议将网络数据流封装到数据报,然后被数据报发送出去;在信息接收端,UDP协议将数据报转换成实际数据内容。
1>首先在UDP网络编程中没有服务器和客户端这种说法,两个Socket之间没有虚拟链路。只是接收和发送报文
2>这里面有两个重要的类:DatagramSocket和DatagramPacket.
DatagramSocket的两个构造函数:
public DatagramSocket():构造数据报套接字并将其绑定到本地主机上任何可用的端口。
public DatagramSocket(int port):创建数据报套接字并将其绑定到本地主机上的指定端口。
在我们下面的DEMO中,UDPServerTest类中先发送数据报,使用的是套接字的无参构造器,而UDPClientTest类中先接收数据报,必须监听某一个端口,所以使用的是套接字的有参构造器。
DatagramPacket的构造函数:
public DatagramPacket(byte buf[], int length):用来接收长度为length的数据包
public DatagramPacket(byte buf[], int length, InetAddress address, int port):用来将长度为length的包发送到指定主机上的指定端口号。
package lesson1220Socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; public class UDPServer2 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(); String str = "hello world"; //构造用于发送的数据包,指定主机和端口号 DatagramPacket packet = new DatagramPacket(str.getBytes(), str.length(), InetAddress.getByName("localhost"), 5555); ds.send(packet); //读取从客户端发送过来的响应 byte[] buffer = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(buffer,buffer.length); ds.receive(packet2); System.out.println("address: " + packet2.getAddress() + " port: "+ packet2.getPort()); String str2 = new String(buffer,0,packet2.getLength()); System.out.println(str2); ds.close(); } } package lesson1220Socket; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class UDPClient2 { public static void main(String[] args) throws Exception { DatagramSocket ds = new DatagramSocket(5555); byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); ds.receive(packet); System.out.println("address: " + packet.getAddress() + " port: "+ packet.getPort()); String str = new String(buffer, 0, packet.getLength()); System.out.println(str); // 接收到数据包之后,客户端返回响应回去 String str2 = "welcome"; DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2 .length(), packet.getAddress(), packet.getPort()); ds.send(packet2); ds.close(); } }
上面的例子,要先运行UDPClient2(接收端先启动) ,然后再运行UDPServer2 ,
运行结果如下:
UDPServer2:
address: /127.0.0.1 port: 5555
welcome
UDPClient2:
address: /127.0.0.1 port: 54071
hello world
1、上面的程序中,第一步是服务器端(暂且以这种叫法来区分这两个类)创建一个UDP套接字,没有指定端口,使用的是系统分配的端口。然后构建了一个数据包,包中指定 了目标机器的ip和端口号。
2、作为客户端,创建了一个UDP套接字,并且绑定了端口,如果想要接收到服务端发送过来的报文,绑定的端口必须和服务器端发送的包中指定的端口一致。
3、客户端打印了包中的内容之后,想要返回一些内容回去。这个时候,服务器端的ip和端口号可以从之前发送过来的数据包中获取。
DatagramPacket packet2 = new DatagramPacket(str2.getBytes(), str2.length(), packet.getAddress(), packet.getPort());
4、在服务器接收数据包的时候,已经不需要再像客户端创建套接字一样去绑定端口了,因为目前监听的端口和客户端发送的包中指定的端口是一样的。
5、打印看下服务器端的ip和监听的端口号:(注意理解下这个地方端口号,不是5555)
serverIp =/127.0.0.1;serverPort=54071
6、其中DatagramSocket的receive(DatagramPacket p)方法在接收到数据包前一直阻塞。
看下面这个例子:各自交互三次:
1 package lesson1220Socket; 2 3 import java.net.DatagramPacket; 4 import java.net.DatagramSocket; 5 import java.net.InetAddress; 6 import java.net.SocketException; 7 8 public class UDPServer { 9 10 public static void main(String[] args) throws Exception { 11 //1:创建服务器端Socket,指定端口 12 DatagramSocket ds = new DatagramSocket(8888); 13 //2、创建数据报,用于接收客户端发送的信息 14 byte [] data = new byte[1024]; 15 DatagramPacket dp = new DatagramPacket(data, data.length); 16 //3、接收客户端发送的数据 17 System.out.println("开始接收数据1111!"); 18 ds.receive(dp); 19 20 //4、读取数据 21 String info = new String(data, 0, dp.getLength()); 22 System.out.println("我是服务端,收到客户端的信息是: "+info); 23 24 25 //5、像客户端响应数据 26 //定义客户端的地址、端口号和数据 27 InetAddress ia = dp.getAddress(); 28 int port = dp.getPort(); 29 System.out.println("dp ia: " + ia + " port: " + port); 30 //组装发送数据报 31 byte []data2 = "你好客户端!".getBytes(); 32 DatagramPacket dp2 = new DatagramPacket(data2, data2.length, ia, port); 33 //响应客户端 34 System.out.println("开始发送数据2222!"); 35 ds.send(dp2); 36 37 38 //6、接收客户端第二次发送的数据 39 System.out.println("开始接受数据3333!"); 40 ds.receive(dp); 41 System.out.println("dp ia: " + dp.getAddress() + " port: " + dp.getPort()); 42 43 //7、读取数据 44 info = new String(data, 0, dp.getLength()); 45 System.out.println("我是服务端,收到第二次客户端的信息是: "+info); 46 47 48 ds.close(); 49 } 50 51 } 52 53 package lesson1220Socket; 54 55 import java.io.IOException; 56 import java.net.DatagramPacket; 57 import java.net.DatagramSocket; 58 import java.net.InetAddress; 59 import java.net.SocketException; 60 61 import sun.io.ByteToCharCp1006; 62 63 public class UDPClient { 64 65 public static void main(String[] args) throws Exception { 66 67 InetAddress ia = InetAddress.getLocalHost(); 68 69 //1:创建客户端端Socket,指定端口和地址 70 DatagramSocket ds = new DatagramSocket(); 71 //2、创建数据报,用于向服务器端发送信息 72 byte [] data = "服务端你好".getBytes(); 73 DatagramPacket dp = new DatagramPacket(data, data.length, ia, 8888); 74 //3、向服务器端发送数据 75 System.out.println("A开始发送数据1111!"); 76 ds.send(dp); 77 78 79 //4、读取数据 80 byte [] data2 = new byte[1024]; 81 DatagramPacket dp2 = new DatagramPacket(data2, data2.length); 82 System.out.println("A开始接收数据2222!"); 83 ds.receive(dp2); 84 85 System.out.println("dp2 ia: " + dp2.getAddress() + " port: " + dp2.getPort()); 86 String info = new String(data2, 0, dp2.getLength()); 87 System.out.println("我是客户端,服务器回的信息是: "+info); 88 89 //5、第二次发送数据 90 DatagramPacket dp3 = new DatagramPacket(data, data.length, dp2.getAddress(), dp2.getPort()); 91 System.out.println("A开始发送数据3333!"); 92 ds.send(dp3); 93 94 ds.close(); 95 96 } 97 98 }
上面这个程序先运行UDPServer, 再运行UDPClient。
运行结果:
UDPServer:
开始接收数据1111!
我是服务端,收到客户端的信息是: 服务端你好
dp ia: /100.98.19.103 port: 56013
开始发送数据2222!
开始接受数据3333!
dp ia: /100.98.19.103 port: 56013
我是服务端,收到第二次客户端的信息是: 服务端你好
UDPClient:
A开始发送数据1111!
A开始接收数据2222!
dp2 ia: /100.98.19.103 port: 8888
我是客户端,服务器回的信息是: 你好客户端!
A开始发送数据3333!
参考帖子:
https://www.cnblogs.com/dongguacai/p/5747603.html
https://www.cnblogs.com/dongguacai/p/5747397.html
https://www.cnblogs.com/rocomp/p/4790340.html-------基础讲解
https://www.cnblogs.com/Qian123/tag/java%E5%9F%BA%E7%A1%80/default.html?page=3
https://www.cnblogs.com/yiwangzhibujian/p/7107785.html
https://blog.csdn.net/facekbook/article/details/55506347
其他基础:
https://blog.csdn.net/hguisu/article/category/1122753
https://www.cnblogs.com/dolphin0520/category/602384.html
关于TCP/IP中更多的例子请看另一篇关于Socket多线程编程!
以上是关于Java 网络编程的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段14——Vue的axios网络请求封装
VSCode自定义代码片段14——Vue的axios网络请求封装