JAVA基础-网络编程

版权声明:gitboy https://blog.csdn.net/weixin_40160543/article/details/89607750

类 InetAddress

此类表示互联网协议 (IP) 地址。

IP 地址是 IP 使用的 32 位或 128 位无符号数字,它是一种低级协议,UDP 和 TCP 协议都是在它的基础上构建的。IP 地址的体系结构是由 RFC 790:Assigned

Numbers RFC 1918:Address Allocation for Private InternetsRFC 2365:Administratively Scoped

IP MulticastRFC 2373:IP Version 6 Addressing

Architecture 定义的。InetAddress 的实例包含 IP

地址,还可能包含相应的主机名(取决于它是否用主机名构造或者是否已执行反向主机名解析)。

网络编程三要素:

A:IP地址

B:端口

C:协议

public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
// public static InetAddress getByName(String host)
// InetAddress address = InetAddress.getByName("liuyi");
// InetAddress address = InetAddress.getByName("192.168.12.92");
InetAddress address1 = InetAddress.getByName("172.16.102.58");
InetAddress[] address2 = InetAddress.getAllByName("172.16.102.58");
// 获取两个东西:主机名,IP地址
// public String getHostName()
// public String getHostAddress()
String name1 = address1.getHostName();
String ip1 = address1.getHostAddress();

for (InetAddress inetAddress : address2) {
System.out.println(inetAddress);
}

System.out.println(name1 + "---" + ip1);
}
}

IP地址:

网络中计算机的唯一标识。

计算机只能识别二进制的数据,所以我们的IP地址应该是一个二进制的数据。

但是呢,我们配置的IP地址确不是二进制的,为什么呢?

IP:192.168.1.100

换算:11000000 10101000 00000001 01100100

假如真是:11000000 10101000 00000001 01100100的话。

我们如果每次再上课的时候要配置该IP地址,记忆起来就比较的麻烦。

所以,为了方便表示IP地址,我们就把IP地址的每一个字节上的数据换算成十进制,然后用.分开来表示:

"点分十进制"

IP地址的组成:网络号段+主机号段

A类:第一号段为网络号段+后三段的主机号段

一个网络号:256*256*256 = 16777216

B类:前二号段为网络号段+后二段的主机号段

一个网络号:256*256 = 65536

C类:前三号段为网络号段+后一段的主机号段

一个网络号:256

IP地址的分类:

A类 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址) (2)127.X.X.X是保留地址,用做循环测试用的。

B类 128.0.0.1---191.255.255.254 172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。

C类 192.0.0.1---223.255.255.254 192.168.X.X是私有地址

D类 224.0.0.1---239.255.255.254

E类 240.0.0.1---247.255.255.254

两个DOS命令:

ipconfig 查看本机ip地址

ping 后面跟ip地址。测试本机与指定的ip地址间的通信是否有问题

特殊的IP地址:

127.0.0.1 回环地址(表示本机)

x.x.x.255 广播地址

x.x.x.0 网络地址

端口号:

正在运行的程序的标识。

有效端口:0~65535,其中0~1024系统使用或保留端口。

协议:

通信的规则

UDP:

把数据打包

数据有限制

不建立连接

速度快

不可靠

TCP:

建立连接通道

数据无限制

速度慢

可靠

举例:

UDP:发短信

TCP:打电话

Scoket

--java.net

-- --DatagramSocket

此类表示用来发送和接收数据报包的套接字。

-- --DatagramPacket

此类表示数据报包。

数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。

UDP协议发送数据:

A:创建发送端Socket对象

B:创建数据,并把数据打包

C:调用Socket对象的发送方法发送数据包

D:释放资源

 public class SendDemo {
public static void main(String[] args) throws IOException {
// 创建发送端Socket对象
// DatagramSocket()
DatagramSocket ds = new DatagramSocket();

// 创建数据,并把数据打包
// DatagramPacket(byte[] buf, int length, InetAddress address, int port)
// 创建数据
byte[] bys = "hello,udp,我来了".getBytes();
// 长度
int length = bys.length;
// IP地址对象
InetAddress address = InetAddress.getByName("172.16.102.58");
// 端口
int port = 10010;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);

// 调用Socket对象的发送方法发送数据包
// public void send(DatagramPacket p)
ds.send(dp);

// 释放资源
ds.close();
}
}

UDP协议接收数据:

A:创建接收端Socket对象

B:创建一个数据包(接收容器)

C:调用Socket对象的接收方法接收数据

D:解析数据包,并显示在控制台

E:释放资源

 public class ReceiveDemo {
public static void main(String[] args) throws IOException {
// 创建接收端Socket对象
// DatagramSocket(int port)
DatagramSocket ds = new DatagramSocket(10010);

// 创建一个数据包(接收容器)
// DatagramPacket(byte[] buf, int length)
byte[] bys = new byte[1024];
int length = bys.length;
DatagramPacket dp = new DatagramPacket(bys, length);

// 调用Socket对象的接收方法接收数据
// public void receive(DatagramPacket p)
ds.receive(dp); // 阻塞式

// 解析数据包,并显示在控制台  
// 获取对方的ip
// public InetAddress getAddress()
InetAddress address = dp.getAddress();
String ip = address.getHostAddress();
// public byte[] getData():获取数据缓冲区
// public int getLength():获取数据的实际长度
byte[] bys2 = dp.getData();
int len = dp.getLength();
String s = new String(bys2, 0, len);
System.out.println(ip + "传递的数据是:" + s);

// 释放资源
ds.close();
}
}

TCP协议发送数据:

A:创建发送端的Socket对象

这一步如果成功,就说明连接已经建立成功了。

B:获取输出流,写数据

C:释放资源

TCP协议接收数据:

A:创建接收端的Socket对象

B:监听客户端连接。返回一个对应的Socket对象

C:获取输入流,读取数据显示在控制台

D:释放资源

 public class ClientDemo {
public static void main(String[] args) throws IOException {
// 创建Socket对象
Socket s = new Socket("192.168.12.92", 34567);

// 封装文本文件
BufferedReader br = new BufferedReader(new FileReader(
"InetAddressDemo.java"));
// 封装通道内的流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));

String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}

br.close();
s.close();
}
}

-- --ServerSocket

此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。

服务器套接字的实际工作由 SocketImpl

类的实例执行。应用程序可以更改创建套接字实现的套接字工厂来配置它自身,从而创建适合本地防火墙的套接字。

public class ServerDemo {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(34567);

// 监听客户端连接
Socket s = ss.accept();

// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));

String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}


s.close();
}
}

利用Socket进行网络通信开发

在网络编程中,接触到最多的就是利用Socket进行网络通信开发。在Java中主要是以下三种实现方式BIO、NIO、AIO。

关于这三个概念的辨析以前一直都是好像懂,但是表达的不是很清楚,下面做个总结完全辨析清楚。

1. BIO方式

首先我用一个较为通俗的语言来说明:

BIO 就是阻塞IO,每个TCP连接进来服务端都需要创建一个线程来建立连接并进行消息的处理。如果中间发生了阻塞(比如建立连接、读数据、写数据时发生阻碍),线程也会发生阻塞,并发情况下,N个连接需要N个线程来处理。

这种方式的缺点就是:并发情况下效率很低

2. NIO方式

NIO是JDK1.4提出的,还是先用一段通俗的话来说明NIO的工作原理:

NIO 也就是非阻塞IO,是基于事件驱动的思想(Reactor线程模型)。对比与BIO来说,NIO使用一个线程来管理所有的Socket 通道,也就是基于Selector机制,当查询到事件时(连接、接受连接、读、写),就会转发给不同的处理线程(handler)。

3. AIO方式

AIO是JDK1.7提出的,也就是异步IO。AIO采用的是Proactor模式。我们首先应该辨析的是AIO和NIO的区别:

(1)NIO的通知是发生在Handler之前;

(2)AIO的通知是发生在读写等处理之后的回调,有通知时表示相关操作已经结束了。

AIO在进行读写操作时,只需要调用相应的read/write方法,并传入CompletionHandler(动作完成时处理器),在动作完成后会调用CompletionHandler。 NIO的通知是发生在动作之前,是在可读可写的时候,Selector发现了这些事件后就通知并调用Handler处理,

下面给出Proactor模式的工作流程图:

猜你喜欢

转载自blog.csdn.net/weixin_40160543/article/details/89607750