网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
实现网络中的主机通信
1.通信双方的地址:IP、端口号
2.一定的规则:网络通信协议(OSI参考模型、TCP、IP协议)
IP地址:对应InetAddress类,一个对象代表一个IP地址;
IP地址分类
IPV4:4个字节组成
IPV6:16个字节,写成8个整数,每个整数用4位十六进制数表示,数之间用冒号隔开(X:X:X:X:X:X:X:X,X=_ _ _ _)
也可以分为
公网地址:万维网使用
私有地址:局域网使用,192.168开头,范围是0.0——255.255
InetAddress类,一个对象代表一个IP地址;
InetAddress inetAddress=InetAddress.getByName("127.0.0.1");
getByName(String host)//InetAddress类中的静态方法,获得IP地址对象
getLocalHost()//静态方法,获取本地IP地址
//常用方法(非静态)
getHostAddress()//获取本地地址
getHostName()//获取本地域名
InetAddress常用方法
序号 | 方法描述 |
---|---|
1 | static InetAddress getByAddress(byte[] addr) 在给定原始 IP 地址的情况下,返回 InetAddress 对象。 |
2 | static InetAddress getByAddress(String host, byte[] addr) 根据提供的主机名和 IP 地址创建 InetAddress。 |
3 | static InetAddress getByName(String host) 在给定主机名的情况下确定主机的 IP 地址。 |
4 | String getHostAddress() 返回 IP 地址字符串(以文本表现形式)。 |
5 | String getHostName() 获取此 IP 地址的主机名。 |
6 | static InetAddress getLocalHost() 返回本地主机。 |
7 | String toString() 将此 IP 地址转换为 String。 |
域名
www.baidu.com
本地回路地址
127.0.0.1 对应localhost
端口号
端口分类
1.公认端口:0——1023,系统的保留端口,程序尽可能别使用这些端口;
2.注册端口:1024——49151
3.动态/私有端口:49152——65515
特定的端口号:MySQl 3306;Tomcat 8080
IP地址和端口号的组合得到一个网络套接字:Socket;
Socket(套接字)用来描述IP地址和端口,是通信链的句柄,应用程序可以通过Socket向网络发送请求或者应答网络请求;
Socket是支持TGP/IP协议的网络通信的基本操作单元,是对网络通信过程中端点的抽象表示,包含了进行网络通信所必须的五种信息:
1.连接所使用的协议;
2.本地主机的IP地址;
3.本地远程的协议端口;
4.远地主机的IP地址;
5.远地进程的协议端口;
public class ServerDemo extends Thread {//服务端
private ServerSocket serverSocket;
public ServerDemo(int port) throws IOException{
serverSocket=new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
@Override
public void run() {
while (true){
try {
System.out.println("等待远程连接,端口号为:"+serverSocket.getLocalPort());
Socket server=serverSocket.accept();
System.out.println("远程主机地址:"+server.getRemoteSocketAddress());
DataInputStream dataInputStream=new DataInputStream(server.getInputStream());
System.out.println(dataInputStream.readUTF());
DataOutputStream dataOutputStream=new DataOutputStream(server.getOutputStream());
dataOutputStream.writeUTF("连接成功"+server.getLocalSocketAddress()+"\nGood bye");
server.close();
}catch (SocketTimeoutException e){
System.out.println("Socket Time Out");
break;
}catch (IOException e){
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
int port=Integer.parseInt(args[0]);
try{
Thread thread=new ServerDemo(port);
thread.run();
}catch (IOException e){
e.printStackTrace();
}
}
}
public class ClientDemo {//客户端
public static void main(String[] args) {
String serverName=args[0];
int port=Integer.parseInt(args[1]);
try{
System.out.println("连接主机:"+serverName+",端口号:"+port);
Socket client=new Socket(serverName,port);
System.out.println("远程主机地址:"+client.getRemoteSocketAddress());
OutputStream outputStream=client.getOutputStream();
DataOutputStream dataOutputStream=new DataOutputStream(outputStream);
dataOutputStream.writeUTF("Hello from"+client.getRemoteSocketAddress());
InputStream inputStream=client.getInputStream();
DataInputStream dataInputStream=new DataInputStream(inputStream);
System.out.println("服务器响应"+dataInputStream.readUTF());
client.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。
ServerSocket 类有四个构造方法:
序号 | 方法描述 |
---|---|
1 | public ServerSocket(int port) throws IOException 创建绑定到特定端口的服务器套接字。 |
2 | public ServerSocket(int port, int backlog) throws IOException 利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。 |
3 | public ServerSocket(int port, int backlog, InetAddress address) throws IOException 使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。 |
4 | public ServerSocket() throws IOException 创建非绑定服务器套接字。 |
ServerSocket 类的常用方法:
序号 | 方法描述 |
---|---|
1 | public int getLocalPort() 返回此套接字在其上侦听的端口。 |
2 | public Socket accept() throws IOException 侦听并接受到此套接字的连接。 |
3 | public void setSoTimeout(int timeout) 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。 |
4 | public void bind(SocketAddress host, int backlog) 将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 |
java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象通过 accept() 方法的返回值。
Socket 类有五个构造方法:
序号 | 方法描述 |
---|---|
1 | public Socket(String host, int port) throws UnknownHostException, IOException. 创建一个流套接字并将其连接到指定主机上的指定端口号。 |
2 | public Socket(InetAddress host, int port) throws IOException 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 |
3 | public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException. 创建一个套接字并将其连接到指定远程主机上的指定远程端口。 |
4 | public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException. 创建一个套接字并将其连接到指定远程地址上的指定远程端口。 |
5 | public Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字 |
Socket类常用方法
序号 | 方法描述 |
---|---|
1 | public void connect(SocketAddress host, int timeout) throws IOException 将此套接字连接到服务器,并指定一个超时值。 |
2 | public InetAddress getInetAddress() 返回套接字连接的地址。 |
3 | public int getPort() 返回此套接字连接到的远程端口。 |
4 | public int getLocalPort() 返回此套接字绑定到的本地端口。 |
5 | public SocketAddress getRemoteSocketAddress() 返回此套接字连接的端点的地址,如果未连接则返回 null。 |
6 | public InputStream getInputStream() throws IOException 返回此套接字的输入流。 |
7 | public OutputStream getOutputStream() throws IOException 返回此套接字的输出流。 |
8 | public void close() throws IOException 关闭此套接字。 |
1.创建ServerSocket和Socket;
2.打开连接到的Socket的输入/输出流;
3.按照协议对Socket进行读写操作;
4.关闭输入输出流以及Socket;
1.创建ServerSocket对象,绑定监听的端口;
2.调用accept()方法监听客户端的请求;
3.服务端与客户端连接建立以后,通过输入流读取客户端发送的请求信息;
4.通过输出流向客户端发送响应信息;
5.关闭相关资源;
public static void main(String[] args) throws IOException {
//1.创建一个服务器端Socket,即ServerSocket,绑定指定的端口,并监听此端口;
ServerSocket serverSocket=new ServerSocket(12345);
InetAddress inetAddress=InetAddress.getLocalHost();
String ip=inetAddress.getHostAddress();
Socket socket=null;
//2.调用accept()方法,等待客户端连接;
System.out.println("服务端已就绪,等待客户端接入,服务端ip地址: " + ip);
socket = serverSocket.accept();
//3.连接后获取输入流,读取客户端信息;
InputStream inputStream=socket.getInputStream();
InputStreamReader inputStreamReader=new InputStreamReader(inputStream,"UTF-8");
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
OutputStream outputStream=null;
PrintWriter printWriter=null;
String info=null;
while((info=bufferedReader.readLine())!=null){//循环读取客户端的信息
System.out.println("客户端发来信息"+info);
socket.shutdownInput();
socket.close();
}
1.创建Socket对象,指明需要连接的服务器的地址和端口号;
2.连接建立以后,通过输出流向服务器发送请求信息;
3.通过输出流获取服务器响应的信息;
4.关闭相关资源;
Socket socket = new Socket("192.168.137.1",12345);//创建客户端Socket,指定服务器和端口
OutputStream outputStream= socket.getOutputStream();//获取输出流,向客户端发送信息
PrintWriter printWriter=new PrintWriter(outputStream);
InetAddress inetAddress = InetAddress.getLocalHost();
String ip=inetAddress.getHostAddress();//获取客户端的IP地址
printWriter.write("客户端ip地址:"+ip+"接入服务器");
printWriter.close();
printWriter.flush();
socket.shutdownOutput();//关闭输出流
socket.close();
UDP通信无需建立发送和接收的连接,通过类DatagramSocket和DatagramPocket实现了基于UDP协议网络通信;
UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据是否一定能够安全地送到目的地,也不能确定什么时候可以送达;
1.创建DatagramSocket,指定端口号;
2.创建DatagramPacket;
3.接收客户端发送的数据信息;
4.读取数据;
public class UDPServer {
public static void main(String[] args) throws IOException {
/*
* 接收客户端发送的数据
*/
//1.创建服务端DatagramSocket,指定端口
DatagramSocket datagramSocket=new DatagramSocket(12345);
//2.创建数据报,用于接收客户端发送的数据
byte[] data1=new byte[1024];//创建字节数组,指定接收的数据包的大小
DatagramPacket datagramPacket1=new DatagramPacket(data1,data1.length);
//3.接受客户端发送的数据
System.out.println("服务端已经启动,等待客户端发送消息");
datagramSocket.receive(datagramPacket1);//此方法在接收到数据报之前会一直堵塞
//4.读取数据
String info=new String(data1,0,datagramPacket1.getLength());
System.out.println("客户端请求是:"+info);
/*
*响应给客户端的数据
*/
//1.定义客户端的地址、端口号、数据
InetAddress inetAddress=datagramPacket1.getAddress();
int port=datagramPacket1.getPort();
byte[] data2=new String("Hello!").getBytes();
//2.创建数据报,包含响应给客户端的数据信息
DatagramPacket datagramPacket2=new DatagramPacket(data2,data2.length,inetAddress,port);
//3.响应客户端
datagramSocket.send(datagramPacket2);
//4.关闭资源
datagramSocket.close();
}
}
1.定义发送的信息;
2.创建DatagramPacket,包含要发送的信息;
3.创建DatagramSocket;
4.发送数据;
public class UDPClient {
public static void main(String[] args) throws IOException {
/*
* 向服务器端发送数据
*/
// 1.定义服务器的地址、端口号、数据
InetAddress address = InetAddress.getByName("localhost");
int port = 8800;
byte[] data = "用户名:admin;密码:123".getBytes();
// 2.创建数据报,包含发送的数据信息
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
// 3.创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
// 4.向服务器端发送数据报
socket.send(packet);
/*
* 接收服务器端响应的数据
*/
// 1.创建数据报,用于接收服务器端响应的数据
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
// 2.接收服务器响应的数据
socket.receive(packet2);
// 3.读取数据
String reply = new String(data2, 0, packet2.getLength());
System.out.println("服务器响应是:" + reply);
// 4.关闭资源
socket.close();
}
}
小结:UDP的Socket通信就是将数据转换为字节,然后放到DatagramPacket(数据报)中,发送的时候需要指明接收者的IP地址和端口号;而接收的时候,用一个字节数组来缓存;
发送和接受都需要DatagramSocket(端对端通信类)对象来send()或者receive();
网络协议对速率、传输代码、代码结构、传输控制参数、出错控制等制定标准;
分层思想:同层间通信、上层调用下层而不再与下一层有联系;
传输层协议
IP协议是网络层的主要协议,支持网络间互为关联的协议;
URL:统一资源定位符,标识Internet上某一资源的地址
URL 是一个网页地址,可以由字母组成,如"www.baidu.com",或互联网协议(IP)地址:192.68.20.50:端口。
URL 只能使用ASCII 字符集来通过因特网进行发送。
scheme://host.domain:port/path/filename
传输协议://主机名:端口号/(路径)/文件名(#片段名?参数列表)
片段名:锚点
参数列表格式:参数名=参数值&参数名=参数值...
定义在java.net包下;
URL常用方法
序号 | 方法描述 |
---|---|
1 | public String getProtocal() 获取URL的协议名 |
2 | public String getHost() 获取URL的主机名 |
3 | public String getPort() 获取URL的端口号 |
4 | public String getPath() 获取URL的文件路径 |
5 | public String getFile() 获取URL的文件名 |
6 | public String getQuery() 获取URL的查询名 |