网络编程
一、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));// 关闭流对象和socketoutputStream.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));}// 关闭流对象和socketinputStream.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);// 关闭流对象和socketbufferedReader.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协议中每个数据报给出了完整地址信息,无须建立发送方和接收方的连接```javapublic 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协议数据包最大64kDatagramPacket 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);// 回复信息给Bbytes = "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协议数据包最大64kdatagramPacket = 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");}}
