目录
1 UDP协议
2 TCP协议
1 UDP协议
UDP通讯协议的特点:
- 将数据封装为数据包。面向无连接。
- 每个数据包大小限制在64K。
- 因为无连接,所以不可靠。
- 因为不需要建立连接,所以速度快。
- UDP通讯是不分服务端和客服端的,只分发送端和接收端。
发送端的使用步骤:
- 建立UDP的服务
- 准备数据,把数据封装到数据包中发送。发送端的数据包要带上IP地址与端口号
- 调用UDP的服务,发送数据
- 关闭资源
/**
1. 发送端
*/
public class Demo1Sender {
public static void main(String[] args) throws IOException {
// 建立UDP的服务
DatagramSocket datagramSocket = new DatagramSocket();
// 准备数据,把数据封装到数据包中
String data = "这是我的第一个UDP的例子!";
// 创建一个数据包
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.getBytes().length, InetAddress.getLocalHost(), 9090);
// 调用UDP的服务发送数据包
datagramSocket.send(packet);
// 关闭资源-----实际上就是释放占用的端口号
datagramSocket.close();
}
}
接收端的使用步骤:
- 建立UDP的服务
- 准备空的数据包接收数据
- 调用UDP的服务接收数据
- 关闭资源
/**
* 接收端
*/
public class Demo1Receive {
public static void main(String[] args) throws IOException {
// 建立UDP的服务,并且要监听一个端口
DatagramSocket socket = new DatagramSocket(9090);
// 准备空的数据包用于存放数据
byte[] buf = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
// 调用UDP的服务接收数据 receive() 是一个阻塞型方法,没有接收到数据包之前会一直等待。
socket.receive(datagramPacket); // 实际上是存储到了byte数组中了。
System.out.println("接收端收到的数据:" + new String(buf, 0, datagramPacket.getLength())); // getLength() 获取数据包存储了几个字节
// 关闭资源
socket.close();
}
}
在UDP协议中,有一个IP地址称作为广播地址,广播地址就是主机号为255的地址。给广播地址发送消息时,在同一个网络段的机器都可以接收到信息。
/*
* 群聊发送端
*/
public class ChatSender extends Thread {
@Override
public void run() {
try {
// 建立UDP的服务
DatagramSocket socket = new DatagramSocket();
// 准备数据,把数据封装到数据包中
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String line = null;
DatagramPacket packet = null;
while((line = bufferedReader.readLine()) != null) {
// 把数据封装到数据包中
packet = new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("10.200.17.255"), 9092);
// 发送数据
socket.send(packet);
}
// 关闭资源
socket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
/**
* 群聊接收端
*/
public class ChatReceive extends Thread{
@Override
public void run() {
try {
// 创建UDP的服务
DatagramSocket socket = new DatagramSocket(9092);
// 准备空的数据包存储数据
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
boolean flag = true;
while(flag) {
socket.receive(packet);
// packet.getAddress() 获取对方数据包的IP地址对象
System.out.println(packet.getAddress().getHostAddress() + "说:" + new String(buf, 0 ,packet.getLength()));
}
// 关闭资源
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ChatMain {
public static void main(String[] args) {
ChatReceive chatReceive = new ChatReceive();
chatReceive.start();
ChatSender chatSender = new ChatSender();
chatSender.start();
}
}
UDP是一个不可靠(数据包可能会丢失)的协议。
什么情况下数据包会出现丢失呢?
- 带宽不足
- CPU的处理能力不足
2 TCP协议
TCP通讯协议的特点:
- TCP是基于IO流进行数据传输的,面向连接。
- TCP进行数据传输时是没有大小限制的。
- TCP是面向连接的,通过三次握手机制保证数据完整性。是可靠协议。
- TCP是面向连接的,所以速度慢。
- TCP是区分客户端与服务端的。
TCP的客户端使用步骤:
- 建立TCP的客户端服务
- 获取对应的流对象
- 写出或读取数据
- 关闭资源
public class Demo1Client {
public static void main(String[] args) throws IOException {
// 建立TCP的服务
Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
// 获取到Socket对象的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 利用输出流对象把数据写出即可
outputStream.write("服务端你好!".getBytes());
// 获取输入流对象,读取服务端回送的数据
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println("客户端接收到的数据:" + new String(buf, 0, length));
// 关闭资源
socket.close();
}
}
ServerSocket的使用步骤:
- 建立TCP服务端的服务
- 接收客户端的连接产生一个Socket
- 获取对应的流对象读取或者写出数据
- 关闭资源
public class Demo1Server {
public static void main(String[] args) throws IOException {
// 建立TCP的服务端,并且监听一个端口
ServerSocket serverSocket = new ServerSocket(9090);
// 接收客户端的连接
Socket socket = serverSocket.accept(); // accept() 接收客户端的连接,该方法也是一个阻塞的方法,没有客户端与其连接时,会一直等待下去。
// 获取输入流对象,读取客户端发送的内容
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println("服务端接收到的数据:" + new String(buf, 0, length));
// 获取输出流对象,向客户端发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("客户端你好啊!".getBytes());
// 关闭资源
serverSocket.close();
}
}
需求:客户端和服务端一问一答聊天。
/**
* 聊天的客户端
*/
public class ChatClient {
public static void main(String[] args) throws IOException {
// 建立TCP的客户端服务
Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
// 获取键盘的输入流,读取数据
BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in));
// 获取Socket的输出流对象
OutputStreamWriter socketOut = new OutputStreamWriter(socket.getOutputStream());
// 获取Socket的输入流对象
BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
// 不断地读取键盘的录入数据,然后把数据写出
while((line = keyReader.readLine()) != null) {
socketOut.write(line + "\r\n"); // 这里写一行数据时,是不会写到\r\n的(readLine方法不会读到\r\n),这样在服务端读一行数据时就读不到\r\n,导致读取数据失败
// 刷新
socketOut.flush();
// 读取服务端回送的数据
line = socketReader.readLine();
System.out.println("服务端回送的数据:" + line);
}
// 关闭资源
socket.close();
}
}
/**
* 聊天的服务端
*/
public class ChatServer {
public static void main(String[] args) throws IOException {
// 建立TCP的服务端服务
ServerSocket serverSocket = new ServerSocket(9090);
// 接收客户端的连接,产生一个Socket
Socket socket = serverSocket.accept();
// 获取键盘的输入流对象
BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in));
// 获取Socket的输出流对象
BufferedWriter keyOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 获取到Socket的输入流对象
BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 读取客户端的数据
String line = null;
while((line = socketReader.readLine()) != null) {
System.out.println("服务端接收到的数据:" + line);
System.out.println("请输入服务端回送的数据:");
line = keyReader.readLine();
keyOut.write(line + "\r\n");
keyOut.flush();
}
// 关闭资源
serverSocket.close();
}
}