Java网络通信编程学习
1. 基础网络知识概念
学习网络通信编程学习之前,先要对相关知识概念有一定了解。
**IP地址:**处于网络上的每一个设备都有一个唯一的标识(地址),这就是IP。
**端口(Port):**一个设备上可能有多个需要通信的对象(应用程序),为了在一个唯一的IP地址上找到正确的对象,需要给每个对象分配唯一的端口(0-65535,其中0-1013为系统保留)。
IP加端口(组成Socket)就可以正确的在网络上的你需要的对象了。
**协议:**找到你需要交流的对象后,这时就需要大家语言相通,否则都不知道对方在说啥了,因此需要一个语言标准,方便大家交流,这就是协议,当下用的就是随处可闻的TCP/IP协议了。
**TCP/IP协议:**
五层模型:
1.网络接口层(链路层):负责接收IP数据包并通过网络发送。
2.网络层(互联层):负责相邻计算机之间的通信,主要IP协议。
3.传输层(主机到主机层):提供应用程序间的通信,主要TCP、UDP协议。
4.应用层:向用户提供常用的应用程序,比如电子邮件、文件传输访问、远程登录等。主要协议有FTP、TELNET、DNS、SMTP、NFS、HTTP。
因为里面包含了很多网络通信协议,因此还叫__TCP/IP协议族(栈)__,用这些协议中最常用的两个协议(均处于传输层)来命名。
__TCP:Transmission Control Protocol 传输控制协议。__
__IP:Internet Protocol 互联网协议。__
2. Java的网络通信功能
Java提供了4个常用类,来针对不同的网络通信层次进行处理:
**InetAddress:**用于标识处理网络上的硬件资源,表示IP地址。
**URL:**统一资源定位符,通过它可以访问处理网络上的资源数据,由协议名称加资源名称构成,中间冒号隔开。
**Socket:**使用TCP协议实现网络通信的类。
**Datagram:**使用UDP协议,将通信内容放在数据报中,进行网络通信。
2.1 InetAddress应用
此类没有构造方法,但是提供了一些静态方法获取实例。
import java.net.*; public class InetAddressTest{ public static void main(String[] args) throws UnknownHostException{ //获取本机的信息 InetAddress address = InetAddress.getLocalHost(); //通过主机名或者IP地址获取信息 //InetAddress address2 = InetAddress.getByName("my-pc"); InetAddress address2 = InetAddress.getByName("192.168.0.104"); System.out.println("计算机名:"+address.getHostName()); System.out.println("IP地址:"+address.getHostAddress()); System.out.println("address对象:"+address); System.out.println("address2 计算机名:"+address2.getHostName()); System.out.println("address2 IP地址:"+address2.getHostAddress()); System.out.println("address2 address对象:"+address2); } }
2.2 URL应用
import java.net.*; import java.io.*; public class UrlDemo{ public static void main(String[] args)throws MalformedURLException,IOException { URL baidu = new URL("http://www.baidu.com"); System.out.println("协议:"+baidu.getProtocol()); System.out.println("主机:"+baidu.getHost()); //如果没有指定,则显示-1 System.out.println("端口:"+baidu.getPort()); //字节流转换为字符流,并用缓冲类包装 InputStream is = baidu.openStream(); InputStreamReader isr = new InputStreamReader(is,"UTF-8"); BufferedReader br = new BufferedReader(isr); //写入本地文件 FileWriter fw = new FileWriter("baidu.txt"); BufferedWriter bw = new BufferedWriter(fw); String line = null; while((line = br.readLine()) != null){ bw.write(line); bw.newLine(); } //关闭资源 bw.close(); fw.close(); br.close(); isr.close(); is.close(); } }
2.3 Socket应
Socket是基于TCP协议进行的。
TCP协议的特点是面向连接,可靠的,有序的,以字节流的方式发送数据。
因为通信是双方的,所以有两个相关类进行处理:客户端Socket,服务端ServerSocket。
通信流程模型:
(img)
__客户端代码:__
import java.net.*; import java.io.*; public class ClientDemo{ //偷懒了,直接抛出Exception了... public static void main(String[] args) throws Exception { //根据指定地址和端口,创建客户端socket Socket client = new Socket("localhost",2222); //获取输出流,发送请求 OutputStream os = client.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("你好,服务器!"); pw.flush(); //关闭输出流 client.shutdownOutput(); //获取服务端输入流 InputStream is = client.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null; while(null != (line = br.readLine())){ System.out.println("服务器说:"+line); } //关闭输入流 client.shutdownInput(); //关闭各类资源 br.close(); is.close(); pw.close(); os.close(); client.close(); } }
__服务端代码:__
import java.net.*; import java.io.*; public class ServerDemo { //偷懒了,直接抛出Exception了... public static void main(String[] args) throws Exception{ //创建服务端的ServerSocket,绑定端口 ServerSocket serverSocket = new ServerSocket(2222); Socket socket = null; System.out.println("***服务器启动,等待客户端的连接***"); while(true){ //开始监听,等待客户端的连接 socket = serverSocket.accept(); //调用并执行多线程 ThreadServerDemo tsd = new ThreadServerDemo(socket); tsd.run(); //查询监听的端口 int port = serverSocket.getLocalPort(); //查询连接的客户端IP地址 InetAddress address = socket.getInetAddress(); System.out.println("当前监听的端口:"+port); System.out.println("当前访问的客户端IP:"+address.getHostAddress()); } } }
__服务端调用的多线程代码:__
import java.net.*; import java.io.*; public class ThreadServerDemo implements Runnable{ Socket socket = null; public ThreadServerDemo(Socket socket){ this.socket = socket; } //实现Runnable接口的run方法,执行线程操作 public void run(){ //输入输出流,用于接收和返回请求 InputStream is = null; InputStreamReader isr = null; BufferedReader br = null; OutputStream os = null; PrintWriter pw = null; try{ //返回套接字的输入流 is = socket.getInputStream(); isr = new InputStreamReader(is); br = new BufferedReader(isr); String line = null; while(null != (line = br.readLine())){ System.out.println("我是服务器,客户端说:"+line); } //关闭输入流 socket.shutdownInput(); //获取套接字的输出流 os = socket.getOutputStream(); pw = new PrintWriter(os); //返回请求并刷新缓冲 pw.write("欢迎您的访问!"); pw.flush(); //关闭输出流 socket.shutdownOutput(); }catch(IOException e){ e.printStackTrace(); }finally{ try{ //关闭资源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); }catch(IOException e){ e.printStackTrace(); } } } }
2.4 Datagram应用
Datagram(数据报)是基于UDP协议的。
UDP协议特点是:无连接、不可靠、无序的,传输速度快。
使用数据包进行通信时,首先需要将通信的信息定义成数据报,然后在数据报中指明需要达到的目标(主机+端口),然后再讲数据报发送出去。
需要使用到两个类:
__DatagramPacket__:表示数据报包。
__DatagramSocket__:表示用来发送和接收数据报包的套接字,进行端到端通信。
__服务端代码:__
import java.net.*; import java.io.IOException; public class UDPServerDemo{ public static void main(String[] args) { try{ /* **接收客户端发送的数据 */ //构造绑定8888端口的套接字 DatagramSocket dataSocket = new DatagramSocket(8888); //构造接收的数据报 byte[] content = new byte[1024]; DatagramPacket dataPacket = new DatagramPacket(content,content.length); System.out.println("===服务器开始监听接收数据==="); //接收数据 dataSocket.receive(dataPacket); //转换为字符串输出 String client = new String(content,0,dataPacket.getLength(),"UTF-8"); System.out.println("我是服务器,客户端说:"+client); /* **向客户端发送的数据 */ //获取客户端的IP,端口 InetAddress address = dataPacket.getAddress(); int port = dataPacket.getPort(); String reContent = "你好,客户端!"; byte[] reData = reContent.getBytes(); //构造返回给客户端的数据报并发送 DatagramPacket dataPacket2 = new DatagramPacket(reData,reData.length,address,port); dataSocket.send(dataPacket2); //关闭套接字 dataSocket.close(); }catch(SocketException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } } }
__客户端代码__
import java.net.*; import java.io.IOException; public class UDPClinetDemo { public static void main(String[] args) { String str = "服务器,你好!"; byte[] content = str.getBytes(); try{ /* **向服务器发送数据 */ //设置获取服务器的地址,端口 int port = 8888; InetAddress address=InetAddress.getByName("localhost"); //构造发送的数据报,并发送数据 DatagramPacket dataPacket = new DatagramPacket(content,content.length,address,port); DatagramSocket dataSocket = new DatagramSocket(); dataSocket.send(dataPacket); /* **接收服务器数据 */ //构造接收的数据报 byte[] serverData = new byte[1024]; DatagramPacket dataPacket2 = new DatagramPacket(serverData,serverData.length); //接收数据 dataSocket.receive(dataPacket2); //处理接收到的数据,调用packet的getLength方法获取接收到的数据长度 String server = new String(serverData,0,dataPacket2.getLength(),"UTF-8"); System.out.println("我是客户端,服务器说:"+server); //关闭套接字 dataSocket.close(); }catch (SocketException e) { e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } } }
3 总结
1.在Socket编程中,对于同一个Socket对象,一般不需要关闭输入输出流,只要关闭Socket对象,会自动关闭对应流。
2.使用TCP传输对象时,可以使用ObjectOutputStream和ObjectInputStream进行处理。
3.使用Socket进行文件的传输时,一般是直接进行字节的读写复制。
- 点赞
- 收藏
- 关注作者
评论(0)