java网络编程
网络编程
网络基础知识:
IP地址:
- 唯一标识主机
- 对于IPV4来说有4个字节,一个字节范围为0~255
- ip地址的组成192.168.1.110 网络地址+主机地址
- IPV6是由于IPV4地址不够用,用于替代IPV4的下一代IP协议

域名和端口号:
- 域名方便记忆(IP地址)
- IP地址找到主机,端口号找到主机里的不同服务
- 在开发中,不要使用0-1024的端口,这些端口一般名花有主了
网络协议(为了让两台主机能够数据传输):
中国人跟中国人说话,听得懂,
你用中国话跟外国人说话,外国人听不懂,语言就是一个协议
而计算机和计算机之间,数据的组织形式,也就是一种协议

TCP和UDP:
TCP:传输控制协议
双向奔赴的爱情,找一个值得的人慢,但是可靠,可以付出很多感情(大量数据)
-
传输前必须三次握手,确认可以进行大量数据传输,可靠
-
通信的两个应用进程:客户端,服务端
-
传输完毕后,需要释放已建立的连接,效率低
三次握手:
客户端 发送消息x给服务器,服务器回应消息x+1和y给客户端,客户到收到x+1确定服务器可以连接到,再发送y+1给服务器,服务器收到,确定客户端收到了自己的消息,正常开始传输
UDP:用户数据协议
不认真对待的爱情很容易找到,快,但是不可靠,不能付出太多感情(不适合传输大量数据)
- 不需要建立连接,不可靠
- 不适合传输大量数据
- 发送接受不需要关闭连接,速度快
InetAddress:
用处:获取本地的ip地址和主机名,通过域名获取其他主机的ip地址和主机名
public static void main(String[] args) throws UnknownHostException {
// 1.获取本机的InetAdddress对象
InetAddress localHost =InetAddress.getLocalHost();
System.out.println(localHost);
// 2.根据主机名获取InetAdddre对象
InetAddress byName = InetAddress.getByName("Producer-2021XC");
System.out.println(byName);
// 3.根据域名返回InetAdddre对象
InetAddress byName1 = InetAddress.getByName("www.baidu.com");
System.out.println(byName1);
// 4.通过对象获取地址
String hostAddress = byName1.getHostAddress();
System.out.println(hostAddress);
// 5.通过对象获取主机名/或者域名
String hostName = byName.getHostName();
System.out.println(hostName);
}
Socket:

- 套接字
- 通信两端都有Socket,是通信的端点
- 网络通信其实就是Socket的通信
- Socket使网络连接成一个流,数据在两个Socket间通过Io传输
- 底层使用的是TCP/IP协议
TCP字节流编程:
基础流程:
- 客户端和服务端是靠socket的数据通道进行传输的
- 启动顺序:必须先启动服务端,再开启客户端,服务端要先监听,而且客户端要是开启,去获取连接也获取不到
- 服务端:获取监听 》获取socket 》获取输入流
- 客户端:获取连接(ip地址,端口号)》 获取输入流
- 每发送完一次信息要记得,设置结束标志
字节流的传输:
服务端:
public static void main(String[] args) throws IOException {
// 思路:
// 1.首先拿到端口号为9999的监听
// 要求没用其他服务监听9999
// 这个serverSocket可以返回多个accept,多个客户端来连接服务器并发
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("===开始监听===");
// 2.接收连接,如果没用客户端连接上这个端口就会阻塞
Socket accept = serverSocket.accept();
System.out.println("成功获取客户端连接");
// 3.通过输入流接收客户端消息
InputStream IS = accept.getInputStream();
System.out.println(IS.getClass());
byte[]buf=new byte[1024];
int readlend=0;
while ((readlend=IS.read(buf))!=-1){
System.out.println(new String(buf,0,readlend));
}
System.out.println("服务端关闭");
IS.close();
accept.close();
serverSocket.close();
}
客户端
public static void main(String[] args) throws IOException {
// 思路:
// 1.连接服务器(ip,端口)
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
// 2.连接后,生成Socket
OutputStream OS = socket.getOutputStream();
// 3.通过输出流,写入数据到数据管道
OS.write("hello,server".getBytes());
System.out.println("客户端关闭");
OS.close();
socket.close();
}
回传:
当客户端发送后,要接收服务端的回传信息,服务端收到后,要向客户端发送消息
注意点:传完(接收)后要设置接收接收标记,不然socket会不知道你是否完成,造成堵塞
accept.shutdownInput();
accept.shutdownOutput();
服务端
public static void main(String[] args) throws IOException {
// 服务端只需要写当前服务的端口号就行了
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端打开");
Socket accept = serverSocket.accept();
System.out.println("获取接收信息:");
InputStream IS = accept.getInputStream();
OutputStream OS = accept.getOutputStream();
byte buf[]=new byte[1024];
int readline=0;
System.out.println("接收到客户端信息");
while ((readline=IS.read(buf))!=-1){
System.out.println(new String(buf,0,readline));
}
// 设置结束标记
accept.shutdownInput();
System.out.println("向客户端回传信息");
OS.write("hello,client".getBytes());
IS.close();
OS.close();
accept.close();
serverSocket.close();
}
}
客户端
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
OutputStream OS = socket.getOutputStream();
InputStream IS = socket.getInputStream();
System.out.println("向服务端发送信息:");
OS.write("hello,server".getBytes());
// 设置结束标记
socket.shutdownOutput();
byte buf[]=new byte[1024];
int readline=0;
System.out.println("接收服务端信息");
while ((readline=IS.read(buf))!=-1){
System.out.println(new String(buf,0,readline));
}
IS.close();
OS.close();
socket.close();
}
用字符流传递字符串
转换流转成字符流(字符流写入后要flush,不然数据进不到管道)其他一样
涉及缓存必须flush
下载文件/上传文件:
思路:
客户端:先读取本地资源,再用socket的输出流,输出到服务端
服务端:先读取socket输入流,再输出到本地磁盘

注意点:
当客户端连接到服务端后,实际上客户端也是通过一个端口来跟服务器连接的,并且不是跟服务端相同的端口,这个端口是由TCP/IP随机分配,不确定
输入流或者输出流不能在shutdownOutput或者另外一个前先退出,不然会造成socket close异常,也就是你的流不能在标记前退出,可能消息没完
netstat:
-
netstat - an查看主机网络情况
-
netstat - an | more分页查看
-
Listening表示那个端口在监听
-
![1641782586301]()
UDP网络编程:
基础流程:
- 特点就是UDP不在乎对方是否收到
- 通过DategramSocket和DategramPacket(数据包)实现了UDP协议网络程序
- 没有明确的服务端和客户端,只有发送端和接收端,所以是通过DategramSocket接收和发送
- 通过DategramPacket封装数据,既然封装了数据,就肯定有拆包的过程
A端
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(8888);
while (true){
Scanner scanner = new Scanner(System.in);
// 发送包并发送数据
System.out.println("发送消息:");
String content = scanner.next();
if (content.equals("退出")){
break;
}
DatagramPacket packetSE = new DatagramPacket(content.getBytes(StandardCharsets.UTF_8), content.length(), InetAddress.getLocalHost(), 9999);
datagramSocket.send(packetSE);
//接收包并输出消息
byte []byteRE=new byte[1024];
DatagramPacket packetRE = new DatagramPacket(byteRE,byteRE.length);
datagramSocket.receive(packetRE);
int length = packetRE.getLength();
byte[] data = packetRE.getData();
System.out.println("收到B端的消息:"+new String(data,0,length));
}
System.out.println("A端退出");
}
B端
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket(9999);
while (true){
// 接收包并输出消息
byte []byteRE=new byte[1024];
DatagramPacket packetRE = new DatagramPacket(byteRE,byteRE.length);
datagramSocket.receive(packetRE);
System.out.println("收到A端");
int length = packetRE.getLength();
byte[] data = packetRE.getData();
String s = new String(data, 0, length);
System.out.println("收到A端的消息:"+s);
if ("退出".equals(s)){
break;
}
// 发送包并发送数据
System.out.println("发送消息");
Scanner scanner = new Scanner(System.in);
String content = scanner.next();
DatagramPacket packetSE = new DatagramPacket(content.getBytes(StandardCharsets.UTF_8), content.length(), InetAddress.getLocalHost(), 8888);
datagramSocket.send(packetSE);
}
System.out.println("B端退出");
}
注意点:
UDP网络编程没有客户端和服务端,都是用DatagramSocket接收和发送,DatagramSocket可以设置不同端路自己的端口号
总结:
- 网络基础知识方面要知道网络中,不同设备的传输,需要IP地址,不同服务的传输需要端口号
- 可以通过InetAddress获取本地的IP地址和端口号等信息
- Socket套接字,底层是TCP/IP,在服务端和客户端都有一个套接字,两个端通过Socket的数据通道传输数据,记住客户端也有端口号,并且是TCP/IP随机分配的,我们可以通过套接字获取到输出和输入的流,套接字会把流放进数据通道进行传输
- TCP网络编程,服务端需要获取监听,没有收到客户端的连接就会阻塞,然后通过套接字输入流获取客户端传来的信息,客户端需要获取套接字并通过IP地址和端口号绑定到服务端,通过输出流将数据输出给服务端
- UDP网络编程,UDP没有服务端和客户端,只有接收端和发送端,并且每一个端都可以是,通过对象DatagramSocket进行接收和发送,通过Datagramapack进行封装数据,接收端要拆包,设置接收的字节数组和长度,客户端设置传入的字节数组和IP地址,端口号

浙公网安备 33010602011771号