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网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

JAVA之AOP

java代码在片段活动中不起作用

java 代码片段【JAVA】