网络编程
一、TCP和UDP
- TCP 传输控制协议
- 使用前须先建立TCP连接,形成传输数据通道
- 传输前,采用三次握手方式,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可以进行大数据量的传输
- 传输完毕要释放已建立的连接,效率低
UDP 用户数据协议
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据包大小64k内,不适合传输大量数据
- 无需连接,不可靠
-
二、InetAddress类
获取本机InetAddress对象 getLocalHost
根据指定主机名/域名获取ip地址对象 getByName
获取InetAddress对象的主机名 getHostName
获取InetAddress对象的地址 getHostAddresspublic class InetAddress1 {
public static void main(String[] args) throws UnknownHostException {
// 获取本机的InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost); // 输出设备名称/ip地址
// 根据主机名获得InetAddress对象
InetAddress byName = InetAddress.getByName("DESKTOP-I48QCK0");
System.out.println(byName); // 输出设备名称/ip地址
// 根据域名返回InetAddress对象
InetAddress byName1 = InetAddress.getByName("www.baidu.com");
System.out.println(byName1); // www.baidu.com/112.80.248.76
// 通过InetAddress对象获取对应的地址
String hostAddress = byName1.getHostAddress();
System.out.println(hostAddress); // 182.61.200.6
// 通过InetAddress对象获得主机名/域名
String hostName = byName1.getHostName();
System.out.println(hostName); // www.baidu.com
}
}
三、Socket(套接字)
通信的两端都要有Socket,是两台机器间通信的断电
网络通信是Socket间的通信,Socket允许程序把网络当成一个流,数据在两个Socket间通过IO传输四、TCP网络编程
4.1 使用字节流
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
// 1. 9999端口监听,等待连接
// ServerSocket可以通过accept()返回多个Socket,多个客户端连接 并发
ServerSocket serverSocket = new ServerSocket(9999); // 前提是端口没被占用
// 2. 没有客户端连接该端口,程序阻塞,等待连接;有客户端连接,返回socket对象继续执行
Socket socket = serverSocket.accept();
// 3. 通过socket.getInputStream()读取客户端写入到数据通道的数据
InputStream inputStream = socket.getInputStream();
// 4. 读取
byte[] bytes = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes,0, readLen));
}
// 5. 关闭流
inputStream.close();
socket.close();
serverSocket.close();
}
}
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
// 连接服务器 连接成功 返回socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
// socket.getOutputStream()得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 通过输出流,写入数据到数据通道
outputStream.write("hello".getBytes(StandardCharsets.UTF_8));
// 关闭流对象和socket
outputStream.close();
socket.close();
System.out.println("客户端关闭");
}
}
客户端发送,并接收服务端;服务端接收,并发送
public class SocketTCP02Server {
public static void main(String[] args) throws IOException {
// 1. 9999端口监听,等待连接
// ServerSocket可以通过accept()返回多个Socket,多个客户端连接 并发
ServerSocket serverSocket = new ServerSocket(9999); // 前提是端口没被占用
// 2. 没有客户端连接该端口,程序阻塞,等待连接;有客户端连接,返回socket对象继续执行
Socket socket = serverSocket.accept();
// 3. 通过socket.getInputStream()读取客户端写入到数据通道的数据
InputStream inputStream = socket.getInputStream();
// 4. 读取
byte[] bytes = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes,0, readLen));
}
// 5. 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,client".getBytes(StandardCharsets.UTF_8));
// 设置结束标记
socket.shutdownOutput();
// 6. 关闭流
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
public class SocketTCP02Client {
public static void main(String[] args) throws IOException {
// 连接服务器 连接成功 返回socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
// socket.getOutputStream()得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 通过输出流,写入数据到数据通道
outputStream.write("hello".getBytes(StandardCharsets.UTF_8));
// 设置结束标记
socket.shutdownOutput();
// 获取和socket关联的输入流,读取数据(字节)并显示
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, readLen));
}
// 关闭流对象和socket
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客户端关闭");
}
}
4.2 使用字符流
public class SocketTCP03Server {
public static void main(String[] args) throws IOException {
// 1. 9999端口监听,等待连接
// ServerSocket可以通过accept()返回多个Socket,多个客户端连接 并发
ServerSocket serverSocket = new ServerSocket(9999); // 前提是端口没被占用
// 2. 没有客户端连接该端口,程序阻塞,等待连接;有客户端连接,返回socket对象继续执行
Socket socket = serverSocket.accept();
// 3. 通过socket.getInputStream()读取客户端写入到数据通道的数据
InputStream inputStream = socket.getInputStream();
// 4. 读取
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 5. 获取socket相关联的输出流
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,client");
bufferedWriter.newLine(); // 换行符表示结束
bufferedWriter.flush(); // 刷新
// 6. 关闭流
bufferedReader.close(); // 关闭外层流
bufferedWriter.close();
socket.close();
serverSocket.close();
}
}
// 字符流
public class SocketTCP03Client {
public static void main(String[] args) throws IOException {
// 连接服务器 连接成功 返回socket对象
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
// socket.getOutputStream()得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 通过输出流,写入数据到数据通道
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,server");
bufferedWriter.newLine(); // 插入一个换行符,表示写入的内容结束 此时服务端要用readLine()读
bufferedWriter.flush(); // 字符流要手动刷新
// 设置写入结束标记
socket.shutdownOutput();
// 获取和socket关联的输入流,读取数据(字节)并显示
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 关闭流对象和socket
bufferedReader.close(); // 关闭外层流
bufferedWriter.close();
socket.close();
System.out.println("客户端关闭");
}
}
TCP传输
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
// 1. 监听本机端口
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端监听ing");
// 2. 等待连接
Socket socket = serverSocket.accept();
// 3. 读取客户端发送的数据
// 得到输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
// 4. 将数据写入到指定的路径
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("C:\\Users\\ace\\Desktop\\b.png"));
bufferedOutputStream.write(bytes);
bufferedOutputStream.close();
// 向客户端回复收到
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("收到");
bufferedWriter.flush();
socket.shutdownOutput();
// 关闭资源
bufferedWriter.close();
bufferedInputStream.close();
socket.close();
serverSocket.close();
}
}
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
// 客户端连接
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 创建读取磁盘文件的输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("C:\\Users\\ace\\Desktop\\a.png"));
// bytes就是文件对应的字节数组
byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
// 通过socket获取到输出流,将bytes数据发送给服务端
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
bufferedOutputStream.write(bytes); // 将文件写入通道
bufferedInputStream.close();
socket.shutdownOutput(); // 设置写入数据结束
// 接收服务端消息
InputStream inputStream = socket.getInputStream();
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);
// 关闭流
bufferedOutputStream.close();
socket.close();
}
}
```java public class StreamUtils { /**
- 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]
- @param is
- @return
- @throws Exception
*/
public static byte[] streamToByteArray(InputStream is) throws Exception{
ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
byte[] b = new byte[1024];//字节数组
int len;
while((len=is.read(b))!=-1){//循环读取
} byte[] array = bos.toByteArray();//然后将bos 转成字节数组 bos.close(); return array; } /**bos.write(b, 0, len);//把读取到的数据,写入bos
- 功能:将InputStream转换成String
- @param is
- @return
@throws Exception */
public static String streamToString(InputStream is) throws Exception{ BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder builder= new StringBuilder(); String line; while((line=reader.readLine())!=null){
builder.append(line+"\r\n");
} return builder.toString();
}
}
<a name="BKbPF"></a>
## 五、UDP网络编程
类DatagramSocket和DatagramPacket[数据报]实现了基于UDP协议网络程序<br />UDP数据报通过数据报套接字DatagramSocket发送和接收,不保证安全<br />DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址、端口号以及接收端IP地址和端口号<br />UDP协议中每个数据报给出了完整地址信息,无须建立发送方和接收方的连接
```java
public class UDPReceiveA {
public static void main(String[] args) throws IOException {
// 1. 创建DatagramSocket对象
DatagramSocket datagramSocket = new DatagramSocket(9999);
// 2. 构建一个DatagramPacket对象准备接收数据
byte[] bytes = new byte[1024]; // UDP协议数据包最大64k
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
// 3. 调用接收方法
datagramSocket.receive(datagramPacket);
// 4. packet进行拆包 取出数据并显示
int length = datagramPacket.getLength(); // 实际接收到的数据长度
byte[] data = datagramPacket.getData();
String s = new String(data, 0, length);
System.out.println(s);
// 回复信息给B
bytes = "hi".getBytes(StandardCharsets.UTF_8);
datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName(ip), 9998);
datagramSocket.send(datagramPacket);
// 5. 关闭
datagramSocket.close();
System.out.println("A close");
}
}
public class UDPSenderB {
public static void main(String[] args) throws IOException {
// 创建DatagramSocket准备发送和接收数据
DatagramSocket datagramSocket = new DatagramSocket(9998);
// 装包
byte[] bytes = "hello".getBytes(StandardCharsets.UTF_8);
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName(ip), 9999);
datagramSocket.send(datagramPacket);
// B接收
// 1. 构建一个DatagramPacket对象准备接收数据
bytes = new byte[1024]; // UDP协议数据包最大64k
datagramPacket = new DatagramPacket(bytes, bytes.length);
// 2. 调用接收方法
datagramSocket.receive(datagramPacket);
// 3. packet进行拆包 取出数据并显示
int length = datagramPacket.getLength(); // 实际接收到的数据长度
byte[] data = datagramPacket.getData();
String s = new String(data, 0, length);
System.out.println(s);
// 关闭资源
datagramSocket.close();
System.out.println("B close");
}
}