网络编程
所谓的“网络编程”,其实就是编写程序,实现同一个网络中的不同设备之间的通信, 实现数据的传递。
机器通信必须要满足的条件
一个网络中的不同设备,如果需要进行通信,必须满足的条件:
- 需要知道对方的IP地址。
- 需要知道对方的哪一个端口接收数据。
- 需要遵循相同的通信协议。
IP地址
IP:Internet Protocol(网络互连协议)。在计算机中,使用IP地址来描述一个上网设备的唯一地址编号。分为IPv4, IPv6
IPv4: 使用4个字节来描述一个IP地址,由四部分组成,每一个部分一个字节。
IPv6: 使用6个字节来描述一个IP地址,由六部分组成。
端口
端口是一个计算机设备在与外界进行通信的数据的出口和入口,端口号:[0, 65535]
常见的端口号:
- 3306:mysql
- 1521:oracle
- 8080:tomcat
通信协议
HTTP/TCP/UDP...
七层网络分层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
TCP
是一个传输层的通信协议,是一个安全的、面向连接的通信协议。所谓安全,指的是在数据传递的过程中,不会出现数据丢失的情况。
特点:安全的,面向连接的。
面向连接
在TCP中,有两个角色:客户端、服务端。在通信之前,客户端和服务端需要先建立一个安全的连接,数据的传递可以得到保障。
三次握手
在TCP中,连接的建立需要经历如下几个步骤:
- 建立连接时,由客户端向服务端发送一个syn 包,syn包中是一个同步序列编号。发送完之后,客户端进入到 SYN_SENT 状态,等待服务端确认。
- 服务端收到syn包之后,服务端必须确认客户端的syn包信息,同时自己也发送一个syn包给客户端,即SYN_ACK包。服务端进入到SYN_RECV状态。
- 客户端在接收到SYN_ACK包之后,向服务端回复一个ACK 包。此时客户端和服务端都会进入到TCP连接成功状态。SATABLISHED。
几个常见的类
- InetAddress:是一个用来描述IP地址的类。
- Socket:套接字类,描述TCP中的客户端。
- ServerSocket:描述TCP中的服务端。
- DatagramSocket:描述UDP中的需要通信的设备。
InetAddress练习
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
try {
//获取本机
InetAddress localHost=InetAddress.getLocalHost();
System.out.println(localHost);//DESKTOP-1E1HCB6/192.168.131.1 主机名/Ip地址
//通过主机名获取一个主机
InetAddress host1=InetAddress.getByName("DESKTOP-1E1HCB6");
System.out.println(host1);//DESKTOP-1E1HCB6/192.168.131.1
//通过一个IP地址字符串获取主机
InetAddress host2=InetAddress.getByName("192.168.131.1");
System.out.println(host2);// /192.168.131.1
//通过域名来获取主机
InetAddress host3=InetAddress.getByName("www.baidu.com");//www.baidu.com/183.232.231.174
System.out.println(host3);
//通过域名获取所有主机
InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
//www.baidu.com/183.232.231.174
//www.baidu.com/183.232.231.172
for (InetAddress inetAddress : allByName) {
System.out.println(inetAddress);
}
//通过一个IP地址,获取一个主机。IP地址存入到一个byte数组中,若越界就强转
InetAddress byAddress = InetAddress.getByAddress(new byte[]{(byte) 192, (byte) 168, (byte) 131, 1});
System.out.println(byAddress);// /192.168.131.1
//通过一个主机来获取主机姓名
System.out.println(localHost.getHostName());//DESKTOP-1E1HCB6
//通过一个主机来获取IP地址字符串
System.out.println(localHost.getHostAddress());//192.168.131.1
//通过一个主机来获取IP地址的字节数组
byte[] address = localHost.getAddress();
System.out.println(Arrays.toString(address));// [-64, -88, -125, 1]
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
客户端和服务器端进行通信1:客户端将hello,world!发送给服务器端
服务器端
先启动服务器端再启动客户端
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author 昊
* @Create 2020/5/6 21:57
* @Description
*/
public class Server {
public static void main(String[] args) {
//ServerSocket(int port):开启一个服务器端,监听某一个端口
//ServerSocket用于描述服务器端程序
//port:端口号
try(ServerSocket serverSocket=new ServerSocket(9527)){
//接收套接字并开始监听
//这个方法会阻塞当前线程,直至建立连接
Socket accept = serverSocket.accept();
//显示客户端信息
InetAddress localAddress = accept.getLocalAddress();
System.out.printf("客户端%s[%s]对您说:",localAddress.getHostName(),localAddress.getHostAddress());
//获取输入流
InputStream inputStream = accept.getInputStream();
// byte[] array=new byte[1024];
// int len=0;
// while ((len=inputStream.read(array))!=-1){
// String s=new String(array,0,len);
// System.out.println(s);
// }
Scanner scanner=new Scanner(inputStream);
while (scanner.hasNextLine()){
System.out.println(scanner.nextLine());
}
}catch (IOException e){
e.printStackTrace();
}
}
}
客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* @Author 昊
* @Create 2020/5/6 21:57
* @Description
*/
public class Client {
public static void main(String[] args) {
//Socket用来描述客户端主程序
//port:端口号
//端口范围是0--65535
// 0-1023通常会被系统占用,最好使用1024-65535
try(Socket socket=new Socket(InetAddress.getLocalHost(),9527)){
//将数据发送给服务器端
//首先获取输出流
OutputStream outputStream = socket.getOutputStream();
//写入数据
outputStream.write("hello,world!".getBytes());
//写入一次flush一下
outputStream.flush();
}catch (IOException e){
e.printStackTrace();
}
}
}
客户端和服务器端进行通信2:客户端将控制台输入的信息发送给服务器端
服务器端
先启动服务器端再启动客户端
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author 昊
* @Create 2020/5/6 21:57
* @Description
*/
public class Server {
public static void main(String[] args) {
try(ServerSocket serverSocket=new ServerSocket(9527)){
Socket accept = serverSocket.accept();
InetAddress localAddress = accept.getLocalAddress();
System.out.printf("客户端%s[%s]向您发送了:",localAddress.getHostName(),localAddress.getHostAddress());
InputStream inputStream = accept.getInputStream();
// Scanner scanner=new Scanner(inputStream);
// while (true){
// String msg = scanner.nextLine();
// System.out.println(msg);
// if(msg.matches("88|886|bye|Bye|拜拜")){
// break;
// }
// }
while (true){
byte[] array=new byte[1024];
int len=0;
len=inputStream.read(array);
String msg=new String(array,0,len);
System.out.println(msg);
if(msg.matches("88|886|bye|Bye|拜拜")){
break;
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}
客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* @Author 昊
* @Create 2020/5/6 21:57
* @Description
*/
public class Client {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
//Socket用于描述客户端程序
try(Socket socket=new Socket(InetAddress.getLocalHost(),9527)){
//获取输出liu
OutputStream outputStream = socket.getOutputStream();
while (true){
//从控制台获取信息
String line = scanner.nextLine();
//拼接换行符
String msg=line+"\n";
//将信息输出
//若服务器用的Scanner
//outputStream.write(msg.getBytes());
//若服务器端用的是byte数组
outputStream.write(line.getBytes());
//flush一下
outputStream.flush();
//终止条件
if(line.matches("88|886|bye|Bye|拜拜")){
break;
}
}
}catch (IOException e){
e.printStackTrace();
}
}
}