文章目录
Java学习第三阶段
网络相关概念
1. IP地址
2. 域名和端口
3. 网络通信协议
4. TCP 和 UDP
网络编程
1. InetAddress 类
package Network01;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddress01 {
public static void main(String[] args) throws UnknownHostException {
//1.获取本机的InetAddress对象 getLocalHost
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);//DESKTOP-JT4ULL5/192.168.3.5
//2.根据指定主机名,获取InetAddress对象
InetAddress localHost2 = InetAddress.getByName("DESKTOP-JT4ULL5");
System.out.println(localHost2);//DESKTOP-JT4ULL5/192.168.3.5
//3.根据域名返回 InetAddress对象
InetAddress netHost = InetAddress.getByName("www.baidu.com");
System.out.println(netHost);//www.baidu.com/39.156.66.18
//4.通过InetAddress对象获取地址
//ip地址
String ip = netHost.getHostAddress();
System.out.println(ip);//39.156.66.18
//5.通过InetAddress对象获取对应的主机名/域名
String hostName = netHost.getHostName();
System.out.println(hostName);//www.baidu.com
}
}
2. Socket
3. TCP网络通信编程
//状态是LISTENING 表示该端口在监听
// ESTABLISHED 表示有外部端口连接到该端口
//而查看监听某端口的程序是哪个
netstat -anb
netstat -anb|more
我只执行了Socket实例中的Server端,从上面的图片发现 9999 端口是被java程序在监听
服务端的某一确定端口正在监听,如果有客户端希望服务端提供相应服务则连接该确定的端口,而实际上客户端也会有个由TCP/IP分配的端口进行与服务端通信操作
应用实例1:
// 字节流
//1.编写一个服务端和一个客户端
//2.服务端在9999端口监听
//3.客户端连接到服务器端,发送“hello,server”然后退出
//4.服务器端接收到客户端发送的信息,输出,并退出
//Server.java
package Socket_;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//1.在本机的 9999 端口监听,等待连接
//细节:要求 9999 端口没有其他服务在监听
//细节:这个ServerSocket 可以通过accept() 返回多个Socket(多个客户端连接服务器的并发)
ServerSocket serverSocket = new ServerSocket(9999);
//2.当没有客户端连接 9999 端口时,程序会阻塞,并继续监听,等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
System.out.println("Service port 9999 is waiting...");
Socket socket = serverSocket.accept();
//如果serverSocket没有收到连接,则不会执行下面的println
// System.out.println("服务器端socket = "+socket.getClass());
//3.通过socket对象 接收数据通道的数据
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) > 0) {
System.out.println(new String(buffer,0,len));
}
//4.关闭流对象,和socket
inputStream.close();
socket.close();
}
}
//Client.java
package Socket_;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
//1.连接服务端(ip,端口)
// 连接本机的 9999 端口
// 当然也可以连接非本机的ip 和 端口
// 如果连接成功,返回socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端socket返回 = "+socket.getClass());
//2.连接成功后,得到了socket对象,并通过socket对象相关输入输出流进行数据传输,传输到数据通道
OutputStream outputStream = socket.getOutputStream();
//3.通过输出流,写入数据到数据通道
outputStream.write("hello, server".getBytes());
//4.关闭流对象 和 socket,必须关闭,否则其他服务不能接入
outputStream.close();
socket.close();
}
}
应用实例2,实例1的加强版
// 字节流
//1.编写一个服务端和一个客户端
//2.服务端在9999端口监听
//3.客户端连接到服务器端,发送“hello,server”
//4.服务器端接收到客户端发送的信息,输出该信息,并发送”hello,client”给客户端,并退出
//5.客户端接收服务端的信息并输出,然后退出
/*这里加了设置结束标记 shutdownOutput() --结束输出数据 */
//Server.java
package Socket_2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//1.在本机的 9999 端口监听,等待连接
//细节:要求 9999 端口没有其他服务在监听
//细节:这个ServerSocket 可以通过accept() 返回多个Socket(多个客户端连接服务器的并发)
ServerSocket serverSocket = new ServerSocket(9999);
//2.当没有客户端连接 9999 端口时,程序会阻塞,并继续监听,等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
System.out.println("Service port 9999 is waiting...");
Socket socket = serverSocket.accept();
//如果serverSocket没有收到连接,则不会执行下面的println
System.out.println("服务器端socket = "+socket.getClass());
//3.通过socket对象 接收数据通道的数据
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) > 0) {
System.out.println(new String(buffer,0,len));
}
//4.通过socket对象 向数据通道发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,client".getBytes());
//设置结束标记,不然对方不知道你是否结束数据传输了
socket.shutdownOutput();
//5.关闭流对象,和socket
socket.close();
inputStream.close();
outputStream.close();
}
}
//Client.java
package Socket_2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
//1.连接服务端(ip,端口)
// 连接本机的 9999 端口
// 当然也可以连接非本机的ip 和 端口
// 如果连接成功,返回socket对象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端socket返回 = "+socket.getClass());
//2.连接成功后,得到了socket对象,并通过socket对象相关输入输出流进行数据传输,传输到数据通道
OutputStream outputStream = socket.getOutputStream();
//3.通过输出流,写入数据到数据通道
outputStream.write("hello, server".getBytes());
//设置结束标记,不然对方不知道你是否结束数据传输了
socket.shutdownOutput();
//4.获取socket关联的输入流,并读取数据,并显示
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer))>0){
System.out.println(new String(buffer,0,len));
}
//5.关闭流对象 和 socket,必须关闭,否则其他服务不能接入
socket.close();
outputStream.close();
inputStream.close();
}
}
应用实例3:实例2的另外一中方式–字符流
// 字符流
//1.编写一个服务端和一个客户端
//2.服务端在9999端口监听
//3.客户端连接到服务器端,发送“hello,server”
//4.服务器端接收到客户端发送的信息,输出该信息,并发送”hello,client”给客户端,并退出
//5.客户端接收服务端的信息并输出,然后退出
/*这里加了设置结束标记 shutdownOutput() --结束输出数据 */
/*这里设置结束标记也可以是 newLine(), 但是接收方必须用readLine() 来读取数据 */
/*注意:这里 字符流 写完数据必须使用flush(),否则数据无法写入到数据通道
* 字节流 设置结束标记后即可,可以不用flush()
*/
package Socket_3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//1.在本机的 9999 端口监听,等待连接
//细节:要求 9999 端口没有其他服务在监听
//细节:这个ServerSocket 可以通过accept() 返回多个Socket(多个客户端连接服务器的并发)
ServerSocket serverSocket = new ServerSocket(9999);
//2.当没有客户端连接 9999 端口时,程序会阻塞,并继续监听,等待连接
// 如果有客户端连接,则会返回Socket对象,程序继续
System.out.println("Service port 9999 is waiting...");
Socket socket = serverSocket.accept();
//如果serverSocket没有收到连接,则不会执行下面的println
System.out.println("服务器端socket = "+socket.getClass());
//3.通过socket对象 获取socket的字节输入流,并转换为字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//字节流是byte【】,字符流是char【】
char[] buffer = new char[1024];
int len;
while ((len = br.read(buffer)) != -1) {
System.out.println(new String(buffer,0,len));
}
//4.通过socket对象 向数据通道发送数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("hello,client");
//必须加这个 flush() 否则写不到数据通道里去
bw.flush();
//设置结束标记,不然对方不知道你是否结束数据传输了
//也可以使用 osw.newLine()设置结束标记,但是对方读取时要使用readLine()才能读取成功
socket.shutdownOutput();
//5.关闭流对象,和socket
socket.close();
br.close();
bw.close();
}
}
应用实例4:文件操作+网络编程
//1.编写一个服务端和一个客户端
//2.服务端在9999端口监听
//3.客户端连接到服务端,发送一张图片 E:\\view.jpg
//4.服务端接收到客户端发送的图片,保存到src下,发送“收到图片”再退出
//5.客户端接收到服务端发送的“收到图片”,再退出
//Server.java
package HomeWork01;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
System.out.println("Service port 9999 is waiting...");
Socket socket = server.accept();
System.out.println("connect successfully: " + socket.getClass());
OutputStream os = socket.getOutputStream();
FileInputStream fileInputStream = new FileInputStream("E:\\view.jpg");
byte[] bytes = new byte[1024];
int len;
while ((len = fileInputStream.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
socket.shutdownOutput();
os.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
char[] buf = new char[1024];
len = br.read(buf);
String s = new String(buf, 0, len);
if (s.equals("收到图片")) {
System.out.println(s);
br.close();
fileInputStream.close();
os.close();
socket.close();
}
}
}
//Client.java
package HomeWork01;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
FileOutputStream fileOutputStream = new FileOutputStream("E:\\view2.jpg");
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer))!=-1){
fileOutputStream.write(buffer, 0, len);
}
OutputStream outputStream = socket.getOutputStream();
outputStream.write("收到图片".getBytes());
socket.shutdownOutput();
fileOutputStream.close();
outputStream.close();
inputStream.close();
socket.close();
}
}
4. UDP网络通信编程
// 编程步骤
// 1.创建 接收/ 发送端的 DatagramSocket(确认自己要处理的端口号)
// 2.发送方创建DatagramPacket 将数据打包,
// 打包方式,可根据DatagramPacket构造函数来进行
// 其中,创建DatagramPacket要指定发送到哪个主机(ip)的哪个端口
// 3.接收方创建接收DatagramPacket,收到数据后,拆包从而获取数据
// 4,关闭 DatagramSocket
应用实例:
/* 先发后收方 -- 先发送信息给对方,后接收信息并输出,再退出
* 先手后发方 -- 先接收到信息并输出,后发送信息,再退出 */
//先发后收方
//Send.java
package UDP.UDP_1;
import java.io.IOException;
import java.net.*;
public class Send {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket,在 9998 端口接收数据
//主要是发送端和接收端都在同一个机器上,所以选择了两个不同的端口号
//如果不在同一个机器上,则可以选择相同端口号,因为它们的ip都不同
DatagramSocket datagramSocket = new DatagramSocket(9998);
//2.将要发送的数据装包 DatagramPacket
// 并根据接收方的主机名确定接收方的ip地址 ,和 端口号
// 封装的 DatagramPacket对象 :内容,内容长度,主机(IP),端口
// 这里可以查看API文档 查看getByName()可以填主机名,也可以填ip地址
byte[] data = "hello,明天吃火锅".getBytes();
DatagramPacket datagramPacket =
new DatagramPacket(data, data.length, InetAddress.getByName("192.168.3.5"),9999);
//3.发送数据包
datagramSocket.send(datagramPacket);
byte[] buf = new byte[1024];
DatagramPacket receiveInfo = new DatagramPacket(buf, buf.length);
System.out.println("waiting for message...");
datagramSocket.receive(receiveInfo);
int length = receiveInfo.getLength();
byte[] info = receiveInfo.getData();
String receiveData = new String(info,0,length);
System.out.println(receiveData);
datagramSocket.close();
}
}
//先收后发方
//Receive.java
package UDP.UDP_1;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Receive {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket
// 这里明确了接收数据的端口号 9999
DatagramSocket datagramSocket = new DatagramSocket(9999);
//2.构建一个DatagramPacket 对象,准备接收数据
// 注意:一个数据包最大64K
byte[] buf = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
//3.通过接收方法,将通过网络传输的 DatagramPacket 对象填充到 datagramPacket
// 如果没有数据包发送到 9999 端口,则会阻塞
System.out.println("waiting for message...");
datagramSocket.receive(datagramPacket);
//4.可以把packet进行拆包,取出数据,并显示
int length = datagramPacket.getLength();//实际接收到的字节长度
byte[] data = datagramPacket.getData();//接收到的数据
String info = new String(data,0,length);
System.out.println(info);
data = "好呀".getBytes();
DatagramPacket sendPacket = new DatagramPacket(data, data.length, InetAddress.getByName("192.168.3.5"), 9998);
datagramSocket.send(sendPacket);
datagramSocket.close();
}
}