简介
网络编程:是指编写运行在多个设备上的程序,这些设备通过网络连接。
网络编程三要素:
- 协议:TCP、UDP。这两个新协议最重要的区别是:TCP是可靠的,有连接的。UDP是不可靠的,无连接的。
- IP地址:分为IPV4和IPV6两种。本地IP为127.0.0.1或localhost
- 端口号:用来标识设备中的进程(0~65535,1024之前的被系统分配因此不能使用)
java.net包中包含了解决通信问题的类和接口,从而不用关注通信细节。
TCP编程
分为客户端和服务端:
- 客户端:Java中提供了java.net.Socket类用来表示客户端,它向服务器端发出请求,服务器响应则建立连接。
- 服务端:Java中提供了java.net.ServerSocket表示服务端,相当于开启一个服务,等待客户端的连接。
三次握手和四次挥手。
- 三次握手:客户端想服务器发出连接请求。服务器回应客户端确认连接。客户端回应服务器确认连接。
- 四次挥手:客户端请求切断连接。服务器确认收到切断连接请求。服务器发送已经关闭连接信号。客户端应答确认切断。
字节流:客户端和服务端之间通信的数据为字节流。
TCP是全双工通信,因此客户端和服务端都能接收和发送数据,因此都需要创建IO流对象。
服务端通信全过程:
package com.HelloWorld.MySocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);//创建服务端socket对象
Socket socket = serverSocket.accept();//返回的是客户端对象
InputStream inputStream = socket.getInputStream();//创建输入流对象
byte[] bytes = new byte[1024];//创建字节数组
int len = inputStream.read(bytes);//获取字节的长度,并将获取到的字节流读入数组
System.out.println(new String(bytes,0,len));//输出字节数组以字符串方式
OutputStream outputStream = socket.getOutputStream();//创建输出流
byte[] bs = "收到了你的答复客户端".getBytes();//将字符串转化为字节数组
outputStream.write(bs);//写入输出流
socket.close();
serverSocket.close();
}
}
该实例只能用一次,若想多个客户端同时访问需要使用多线程。
- 首先创建服务端socket,设置自己的端口号
- 调用accept()方法返回的是客户端的socket,等待客户端的连接,若无连接则一直等待。
- 使用客户端的socket获取InputStream和OutputStream,并调用read和write方法传递字节流消息。
- 关闭Socket和ServerSocket。
客户端通信全过程:
package com.HelloWorld.MySocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1",8888);//创建客户端对象,构造方法绑定其IP地址和端口号
OutputStream outputStream = socket.getOutputStream();//创建输出流
outputStream.write("你好服务器!".getBytes());//将字节写入流
InputStream inputStream = socket.getInputStream();//创建输入流
byte[] bytes = new byte[1024];//创建字节缓冲区
int len = inputStream.read(bytes);//获取字节的长度
System.out.println(new String(bytes,0,len));//输出,并将字节数组装化为字符串
socket.close();//关闭客户端socket
}
}
- 首先创建客户端socket,将需要连接的服务端的IP地址和端口号输入。
- 使用socket获取InputStream和OutputStream写入和获取与服务端传递的字节流消息。
- 关闭socket。
UDP编程
Java中为UDP编程提供了另一个内置对象:DatagramSocket
同样的分为服务器端和客户端。
服务器端:
package UDP;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class UDPServer {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(6666);
for(;;){
//接收
byte[] bs = new byte[1024];
DatagramPacket p = new DatagramPacket(bs, bs.length);
ds.receive(p);
String s = new String(p.getData(), p.getOffset(), p.getLength(), StandardCharsets.UTF_8);
System.out.println(s);
//发送
byte[] bss = "收到".getBytes();
p.setData(bss);
ds.send(p);
}
}
}
- 创建socket对象
- for死循环,因为其服务器的性质。
- 新建一个UDP包,准备接受数据,包中含有字节缓冲区
- 调用receive方法接受数据,根据String的构造方法将数据转为字符串格式输出
- 发送:一个字符串转为字节数组,放入UDP包中,send方法发送。
客户端:
package UDP;
import java.net.*;
public class UDPClient {
public static void main(String[] args) throws Exception {
//设置客户端配置
DatagramSocket ds = new DatagramSocket();//创建socket
//指的是客户端接收UDP包时等待时间不会超过1秒,如果一秒内没有收到UDP包,则关闭
ds.setSoTimeout(1000);
//connect方法为了在ds实例中保存服务器的IP地址和端口号,以确保只能向该服务器发送(连接)
ds.connect(InetAddress.getByName("localhost"),6666);
//发送:UDP发送的是UDP包,DatagramPacket,包中含有的是字节数组
byte[] data = "Hello".getBytes();//创建数组
DatagramPacket packet = new DatagramPacket(data, data.length);//新建UDP包
ds.send(packet);//发送
//接收:需要创建一个缓冲区,和一个新的UDP包用来接收传递过来的包
byte[] buffer = new byte[1024];
packet = new DatagramPacket(buffer, buffer.length);
ds.receive(packet);//接收包
String resp = new String(packet.getData(), packet.getOffset(), packet.getLength());//将DUP包转换为String字符串
System.out.println(resp);
ds.disconnect();//关闭连接
ds.close();
}
}
- 创建socket实例对象,对客户端实例对象进行配置:设置其等待时间和连接对象的IP和端口号
- 发送:创建所要发送的字节数组,将字节数组放入包内,调用socket实例对象的send方法。注意:DUP包内容的设置可以在初始化时进行以及,使用setData方法。
- 接收:创建一个缓冲区,一个空的UDP包,包内存入字节缓冲区,调用receive方法接收包,将包转化为字符串输出。
- 关闭连接,因为客户端只运行一次,所以关闭连接。