Java网络通信编程学习

举报
PHP是最好的语言! 发表于 2020/06/17 15:37:01 2020/06/17
【摘要】 学好网络基础,走遍天下都不怕!

1. 基础网络知识概念

学习网络通信编程学习之前,先要对相关知识概念有一定了解。

**IP地址:**处于网络上的每一个设备都有一个唯一的标识(地址),这就是IP

**端口(Port):**一个设备上可能有多个需要通信的对象(应用程序),为了在一个唯一的IP地址上找到正确的对象,需要给每个对象分配唯一的端口(0-65535,其中0-1013为系统保留)。

IP加端口(组成Socket)就可以正确的在网络上的你需要的对象了。

**协议:**找到你需要交流的对象后,这时就需要大家语言相通,否则都不知道对方在说啥了,因此需要一个语言标准,方便大家交流,这就是协议,当下用的就是随处可闻的TCP/IP协议了。

**TCP/IP协议:** 

五层模型:

1.网络接口层(链路层):负责接收IP数据包并通过网络发送。

2.网络层(互联层):负责相邻计算机之间的通信,主要IP协议。

3.传输层(主机到主机层):提供应用程序间的通信,主要TCPUDP协议。

4.应用层:向用户提供常用的应用程序,比如电子邮件、文件传输访问、远程登录等。主要协议有FTPTELNETDNSSMTPNFSHTTP

因为里面包含了很多网络通信协议,因此还叫__TCP/IP协议族(栈)__,用这些协议中最常用的两个协议(均处于传输层)来命名。

__TCPTransmission Control Protocol 传输控制协议。__

__IPInternet 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传输对象时,可以使用ObjectOutputStreamObjectInputStream进行处理。

3.使用Socket进行文件的传输时,一般是直接进行字节的读写复制。




【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。