概述
概述:网络通信协议下,不同计算机上运行的程序,可以进行数据传输
例如,A电脑中的飞秋,发送消息给B电脑中的飞秋,需要哪些条件才能发送嗯?
IP地址
- 设备在网络中的地址,是唯一的标识。
端口
- 应用程序在设备中唯一的标识。
协议
- 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议。
IP
ip:全称为:互联网协议地址,也称IP地址,是分配给上网设备的数字标签,常见的IP分类为:ipv4和ipv6
- IPv4: 是网际协议开发过程中的第四个修订版本,也是此协议第一个被广泛部署的版本。IPv4是互联网的核心,也是使用最广泛的网际协议版本,其后继版本为IPv6,直到2011年,IANA IPv4位址完全用尽时,IPv6仍处在部署的初期。
- IPv6:由于IPv4最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍 [1] 。 互联网数字分配机构(IANA)在2016年已向国际互联网工程任务组(IETF)提出建议,要求新制定的国际互联网标准只支持IPv6,不再兼容IPv4。
具体可以通过百度百科了解。
常用命令:
- ipconfig:查看本机IP
- ping IP地址:检查网络是否连通
我们ping一下博客地址,其中47.106.67.159就是我服务器电脑的ip了。可以检测当前电脑与服务器之间是否畅通,同时确定服务器的IP。
特殊IP地址:
- 127.0.0.1:回送地址也称本地回环地址,可以代表本机的IP地址,一般是用来做测试使用。
InetAddress
为了方便我们对IP地址的获取和操作,java提供了一个类InetAddress供我们使用
InetAddress:此类表示Internet协议(IP)地址
具体查看JDK的官方API文档
端口
端口:要用程序在设备中的唯一标识
端口号:用两个字节表示的数据,它的取值范围是0~65535,其中0~1023之间的端口号用于一些知名的网络服务或者应用。我们自己使用1024以上的端口号
注意:一个端口号只能被一个应用程序使用。
协议
协议:计算机网络中,连接和通信的规则被称为网络通信协议
UDP协议
- UDP是面向无连接通信协议。速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据。
- 不管你有没有建立连接,他都会发送出去。
- 常用于:传递音频、数据、普通数据等
TCP协议
- TCP协议是面向连接的通信协议
- 速度慢,没有大小限制,数据安全
总结
网络编程:就是让两台计算机进行数据交互
网络编程三要素
- IP:设备在网络中唯一的标识
- 端口号:应用程序在设备中唯一的标识
- 协议:数据在传输过程中遵循的规则
UDP通信程序
UDP发送数据:
步骤:
- 创建发送端的DatagramSocket对象
- 创建数据,并把数据打包进箱子(DatagramPacket)
- 调用DatagramSocket对象的方法发送数据
- 释放资源
代码示例。
代码语言:javascript复制public class ClientDemo {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
//设置要传输的数据,并转化为byte类型,不能直接穿字符串
String s = "你家孩子被录取了";
byte[] bytes = s.getBytes();
//创建主机且命名为localhost
InetAddress address = InetAddress.getByName("localhost");
//设置端口
int port = 1000;
//保存进箱子
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);
socket.send(packet);
socket.close();
}
}
运行结果为空白,我们没有设置接收端,UDP协议只管发,收不收得到都不管。
UDP接收数据
步骤:
- 创建接收端的DatagramSocket对象
- 创建一个箱子,用于接收数据
- 调用DatagramSocket的方法接收数据并将数据放进箱子中保存
- 解析数据,在控制台显示
- 释放资源
public class ServeDemo {
public static void main(String[] args) throws IOException {
//表示从1000端口接受数据
DatagramSocket socket = new DatagramSocket(1000);
//给箱子设置一个byte数组进行接收
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
socket.receive(packet);
//在控制台打印数据
System.out.println(new String(bytes));
//我们也可以通过getData()方法将箱子里的数据重新拿出,一般不需要
byte[] data = packet.getData();
System.out.println(new String(data));
//记得释放资源
socket.close();
}
}
我们运行起来,发现程序正在运行,但是没有打印出任何东西。
这很正常,因为我们并没有发送数据给它呀,这时我们保持接收端不动,去运行前面已经写好的发送端,他们端口都是1000。
我们看到效果已经出现了!
- 如果你先运行了发送端,它就已经把数据发送出去了,你此时再运行接收端就没有效果了。
- 如果接收端启动之后,没有收到数据,那么它就会死等(阻塞)。也就是它会运行到示例代码中的第9行就等在了那里。
- 在接收数据的时候,需要调用一个getLength方法,表示接收到了多少字节。这里我们使用了1024个字节去接收数据,所以导致我们接收到数据后,后面带了很多空格,具体看下图。所以我们在打印输出中传入长度即可。
System.out.println(new String(bytes,0,packet.getLength()));
UDP通信程序练习
需求:
- UDP发送数据:数据来自键盘录入,直到输入的数据是886,发送数据结束。
- UPD接收数据:因为接收端不知道发送端什么时候停止发送,所以我们采用死循环接收。
public class Serve {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(996);
while (true) {
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
socket.receive(packet);
System.out.println(new String(bytes, 0, packet.getLength()));
}
}
}
代码语言:javascript复制public class Client {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
String s = sc.nextLine();
if ("886".equals(s)){
break;
}
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 996;
DatagramPacket packet = new DatagramPacket(bytes,bytes.length,address,port);
socket.send(packet);
}
socket.close();
}
}
UDP三种通信方式
- 单播,一对一
- 组播,一对多
- 广播,一对所有
UDP通信组播代码实现
组播地址:224.0.0.0~239.255.255.255
其中224.0.0.0~224.0.0.255为预留的组播地址
组播的发送端跟单播类似,也就是跟我们已经演示过的代码类似。但是在单播中,我们是发给指定IP的电脑,在组播中,是发给组播地址。
我们可以看到下面的代码中,我们开头创建了MulticastSocket对象并传入了端口,后面再加入组IP接收数据。这就是组播的接收端示例代码:
代码语言:javascript复制public class Serve2 {
public static void main(String[] args) throws IOException {
MulticastSocket multicastSocket = new MulticastSocket(10000);
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
//把当前计算机绑定一个组播地址,表示添加到这一组中
//注意,这里要跟发送端设置的IP一样
multicastSocket.joinGroup(InetAddress.getByName("224.0.1.0"));
multicastSocket.receive(packet);
System.out.println(new String(bytes,0,packet.getLength()));
}
}
发送端:
代码语言:javascript复制public class Client2 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
String s = "我是乐心湖啊";
byte[] bytes = s.getBytes();
//设置IP
InetAddress address = InetAddress.getByName("224.0.1.0");
int port = 10000;
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);
socket.send(packet);
socket.close();
}
测试,只要你的小伙伴都设置了这个IP和端口(即使用了示例中的接收端),你运行发送端就可以发送 “我是乐心湖啊” 给他们了。
UDP通信广播代码实现
广播地址:255.255.255.255 (必须)
接收端跟单播没有两样。
代码语言:javascript复制public class Serve3 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(10000);
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
socket.receive(packet);
System.out.println(new String(bytes, 0, packet.getLength()));
socket.close();
}
}
代码语言:javascript复制public class Client3 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
String s = "是广播哦";
byte[] bytes = s.getBytes();
//设置IP
InetAddress address = InetAddress.getByName("255.255.255.255");
int port = 10000;
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);
socket.send(packet);
socket.close();
}
}
TCP通信程序
原理:
- TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象。
- 通信之前必须要建立连接
- 通过Socket产生IO流来进行网络通信
TCP发送数据:
步骤:
- 创建客户端的Socket对象与指定服务端连接 , Socket(String host,int port)
- 获取输出流,写数据 OutputStream getOutputStream()
- 释放资源,void close()
此时运行客户端必然报错,因为我们没有写服务端,而TCP协议通信之前必须要建立连接
代码语言:javascript复制public class Client4 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 996);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,leixnhu".getBytes());
outputStream.close();
socket.close();
}
}
TCP接收数据
步骤:
- 创建服务端的Socket对象(ServerSocket) ServerSocket(int port)
- 监听客户端连接,返回一个Socket对象 Socket.accept()
- 获取输入流,读数据,并把数据显示在控制台上 InputSteam getInputStream()
- 释放资源 void close()
public class Serve4 {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(996);
Socket accept = socket.accept();
InputStream inputStream = accept.getInputStream();
int a;
while ((a = inputStream.read())!=-1){
System.out.print((char) a);
}
inputStream.close();
socket.close();
}
}
注意:
- accept方法是阻塞的,为了等待客户端连接
- 客户端创建对象连接服务器,此时是通过三次握手协议保证跟服务器之间的连接。
- 针对客户端来讲,是往外写的,所以是输出流
- 针对服务器来讲,是往里读的,所以是输入流
- read方法也是阻塞的
- 在关流的时候,还多了一个往服务器写结束标记的动作
- 最后一步断开连接,通过四次挥手协议保证连接终止