相关基础概念
计算机网络
是指将地理位置不同,功能独立的多台计算机及其外部设备通过通信的方式连接起来,在网络操作系统,网络管理软件和网络通信协议的协调管理下,实现资源信息共享的计算机系统。
通信连接的方式即可以是无线的,也可以是有线的。
网络编程三要素
所谓网络编程就是使用代码(编程语言)进行不同计算机之间的通信。
一.IP地址
就是指每台计算机的唯一标识,就跟我们的手机电话号码一样,独一无二,通过IP地址,就可以找到这台计算机,并与之进行通信。由一串数字组成。
IP地址的分类:
IPV4:早先因为计算机并不是那么多,所以一开始给每台计算机分配32bit的地址,也就是4个字节。原本是使用二进制表示的,但是由于太难记忆了,就改成十 进制来记忆了,每一个字节为一个十进制,并且用.(英文句号)来分隔开。例如:192.168.137.9。
IPV6:随着计算机的普及,IPV4不够用了(只有大约43亿个地址)。所以采用了IPV6来扩展地址空间,采用了128bit的地址长度。每16个字节为一组,共分为8 组。
与IP地址相关的常用的DOS命令:
- ipconfig: 查看本机的IP地址
- ping ip地址:检查与该ip地址之间的网络是否连通
特殊的一个ip地址
- 127.0.0.1:表示的是本机地址,一般我们在写代码测试的时候,就会将我们的本机地址当成是127.0.0.1,或者是localhost来指代本机地址。
java中的IP地址的抽象表示
java中使用InetAddress类来抽象表示网络协议中的IP地址(可以看成是IP地址在java中的映射),下面讲到的UPD协议和TCP协议中都有用到这个类,其简单使用如下:
public class InetAddressDemo1 {
public static void main(String[] args) throws UnknownHostException {
InetAddress byName = InetAddress.getByName("LAPTOP-4FNIF3OD"); //你电脑的物理名称,可以在自己的电脑中查到
System.out.println(byName.getHostAddress()); //获取IP地址
System.out.println(byName.getHostName()); //获取电脑名称
}
}
二.端口
IP地址是每台计算机的唯一表示,而端口号就是计算机上应用程序的唯一标识,端口号的范围为0-65535。其中0-1023端口号一般都是被一些知名的网络服务程序和应用客户端程序所占用。例如HTTP的端口号为80;SSH的端口号为22,还有例如常见的mysql的端口号为3306;如果一个端口号被占用了,我们启用的程序也是占用该端口号时就会报错。
如果我们就是想用该端口号,可以使用以下命令先将对应的进程杀死(kill)
- Windows系统
- netstat -nao | findstr “端口号”
- tasklist | pid “PID号”
- Linux系统
- netstat -pan | grep 28317
- kill -9 “PID号”
-9为强制关闭
注:如果想查看windows系统所有应用程序的端口号占用情况,可以使用命令:netstat -nao,在本机地址后面使用冒号分隔的数据即是对应的端口号。也可以直接拿着这个根据这个端口号后面的PID去任务管理器->服务找到对应的PID进行关闭。
三.协议
计算机网络中的连接和通信规则称为网络通信协议,常用的有UDP协议和TCP协议;
UDP协议
用户数据报协议 User Datagram Protocol
是一种无线连接协议,通信时通信双方不用确认是否连接,通信双方没有任何反馈信息。只是纯粹的将数据发送出去。由于这种协议省掉了很多额外的操作,例如确认是否连接,接收反馈等操作。因此消耗的资源比较小,通信的效率也比较高。常用来传输音频,视频等数据。但是同时由于不能确认是否连接,因此在传输的过程中可能导致数据丢失。总之,UDP是面向无连接的通信协议。
TCP协议
传输控制协议 Transmission Control Protocol
TCP协议是面向连接的通信协议,即在连接时,先确保在发送端和接受端之间已经建立起来了连接,然后再进行数据的传输。使用TCP协议可以确保在发送端和接受端之间数据传输的可靠无差错,保证数据的安全,一般可以用在上传文件,下载文件或浏览网页中。(http协议就是基于TCP/IP层的)
而确保发送端与接收端已经连接的方式就是TCP著名的“三次握手”。TCP的“三次握手”比较复杂,在面试中经常被问到。属于计算机网络中内容,这里仅仅简述三次握手的概念性的描述过程(感觉这个过程和计算机总线通信中异步通信的全互锁方式很像)。
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认
- 第二次握手,服务器端向客户端反馈一个响应,通知客户端服务器端已经接收到了连接请求
- 第三次握手,客户端再次向服务器端发送确认信息,确认接收到服务端的反馈响应,并建立连接。
补充:
套接字
套接字,Socket,是对网络中不同主机(对应ip地址)中的应用程序(对应端口号)之间进行双向通信的端点的抽象,简单上讲一个套接字就是一个网络上通信的一端,提供了应用程序利用网络协议交换数据的机制。
从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口 。总之就是一个接口。 只不过叫这么叫就是了。
java的网络通信
基于UDP协议的Socket
上面说了udp协议并不是一种安全可靠的网络协议,它在网络通信两端各创建一个Socket对象,两个Socket对象分别只是负责接收,发送数据,彼此之间并没有生联系。java提供了DatagramSocket类作为基于UDP协议的Socket。
构造方法
- 构造数据报套接字并将其绑定到本地主机上的任何可用端口:
public DatagramSocket() throws SocketException {
this(new InetSocketAddress(0));
}
- 构造数据报套接字并将其绑定到本地主机的指定端口,即要传入一个端口号:
public DatagramSocket(int port) throws SocketException {
this(port, null);
}
- 创建一个数据报套接字,并将其绑定到指定的地址:
public DatagramSocket(int port, InetAddress laddr) throws SocketException {
this(new InetSocketAddress(laddr, port));
}
上面三种构造方法都是直接或者间接的调用了下面这个构造方法:
public DatagramSocket(SocketAddress bindaddr) throws SocketException {}
其中InetSocketAddress类继承了SocketAddress类,可简单的将这两个类看成是套接字Socket地址的抽象(包括该套接字所在的主机的IP地址和对应应用程序的端口号,毕竟网络通信是发生在两台主机之间,要有IP地址才能通信吧~,与上面的InetAddress类似)。
常用方法
- 发送数据报包
public void send(DatagramPacket p);
其中DatagramPacket为数据报包对象,里面封装了要发送的数据,接受的主机IP地址,应用程序的端口号等。(后面会讲到DatagramPacket类的简单用法)
- 接收数据报包
public synchronized void receive(DatagramPacket p);
将该套接字上的接收到数据放在数据报包对象p中,并且是采用同步的方式进行数据的接受。
- 关闭数据报套接字
void close();
------------补充分割线------------------
补充:数据报包对象DatagramPacket类的使用方法
构造方法:
- 发送一个长度为length的字节数据的数据包到指定主机的指定端口号上
参数:address 为要发送数据报包的目的主机IP地址的抽象表示
port 为数据要发送到该主机的哪个端口号
public DatagramPacket(byte[] buf, int length, InetAddress address, int port);
- 构造一个DatagramPacket用于接收长度为length的字节数据的数据包,存在在字节数组参数中
public DatagramPacket(byte[] buf, int length);
注:只要提前准备好用于保存数据的字节数组,直接调用接收或者发送的构造方法即可创建用于接收或者发送的数据报包。
---------补充分割线--------------------
使用DatagramPacket发送数据
发送数据的大致过程可如下:
- 创建一个DatagramSocket对象
DatagramSocket datagramSocket = new DatagramSocket();
- 准备字节要发送的字节数据并创建DatagramPacket对象
byte[] buf = new byte[1024];
//...数据准备
DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getByName("主机名称"), 10086);
- 调用send方法发送数据
datagramSocket.send(packet);
- 关闭DatagramSocket对象
datagramSocket.close();
代码演示如下:
public class SocketDemo1 {
public static void main(String[] args) throws IOException, UnknownHostException {
//1, 创建DatagramSocket对象
DatagramSocket datagramSocket = new DatagramSocket();
//2, 创建数据包
byte[] bys = "hello world".getBytes();
//把主机名改一下即可,并指定对象的接收端口号为10086
DatagramPacket packet = new DatagramPacket(bys, bys.length, InetAddress.getByName("..."), 10086);
//3,发送数据
datagramSocket.send(packet);
//4,关闭连接
datagramSocket.close();
}
}
使用DatagrampPacket接收数据
接收数据的大致过程如下:
- 创建一个DatagramSocket对象,并要指定接受数据的端口,
DatagramSocket socket = new DatagramSocket(10086);
- 创建字节数组和Datagrampacket的接收数据对象
byte[] buff = new byte[1024];
DatagramPacket packet1 = new DatagramPacket(buff, 1024);
- 调用receive方法获取数据
socket.receive(packet1);
- 关闭资源
socket.close();
代码演示如下:接受上面发送代码中发送的“hello world”数据
public class ScoketDemo2 {
public static void main(String[] args) throws IOException {
//1 创建套接字对象 - 指定接受端口
DatagramSocket socket = new DatagramSocket(10086);
//2, 创建数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
//3,接受数据
socket.receive(packet);
//4, 解析接受到的数据
byte[] data = packet.getData();
int length = packet.getLength();
System.out.println(new String(data, 0, length)); //可以看到控制台会打印hello world
socket.close();
}
}
注:在运行代码的时候要先运行接收端的代码,让接收端等待接收,之后再打开发送端的代码,这样接收端才能接收得到发送端发送的数据。
PS:关于udp协议就先到这里吧,后面再写TCP协议~