目录
方法一
重点思路:
用接收结束的时间减去开始发送的时间得到一个时间差——发送...的时长,在一个循环体内通过这个时间差判断发送的东西是否丢失,是否超时重传,是否成功接收并模拟相应操作。
Server.java代码:
package ...;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.temporal.ValueRange;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class SocketServer {
public static int port =8080;
public static void main(String [] agres){
ServerSocket serverSocket = null;
BufferedReader bufferedReader = null;
PrintWriter writer = null;
Socket socket = null;
//设定服务端的端口号
try {
serverSocket=new ServerSocket(port);
//等待请求,此方法会一直阻塞,直到获得请求才往下走
socket=serverSocket.accept();
//用于接收客户端发来的请求,得到输入流
bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//用于发送返回信息,可以不需要装饰这么多io流使用缓冲流时发送数据要注意调用.flush()方法
writer=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
int i=0;
while(i<10) {if(i==0){
String str=bufferedReader.readLine();//接收到的信息
String[] split = str.split(":");
if(split[1].equals("body"+i))
{
writer.println("body"+(i+1));
writer.flush();
i++;
}
}
else {
String str=null;
long l = System.currentTimeMillis();
try {
try {
str = bufferedReader.readLine();//接收到的信息
} catch (IOException e) {
e.printStackTrace();
}
long l1 = System.currentTimeMillis();
String[] split = str.split(":");
if(split.length<1){
System.out.println("丢失");
}
System.out.println(str);
if ( l1 - l < 1 && i != 9&&split.length>1) {
if(split[1].equals("body" + i)){
writer.println("body" + (i + 1));
writer.flush();
i++;}
else{
writer.println("body" + i + "错误重传");
writer.flush();
}
} else {
if (i != 9) {
writer.println("body" + i + "重传");
writer.flush();
} else {
System.out.println("结束");
}
}
} finally {
}
}}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
writer.close();
socket.close();
serverSocket.close();
}catch (Exception e){
}
}
}}
Client.java代码:
package ...;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Scanner;
public class SocketClient {
public static void main(String [] args){
Socket socket=null;
BufferedReader reader=null;
PrintWriter writer=null;
try {
ArrayList<Integer>a=new ArrayList<>();
for (int i = 0; i < 10; i++) {
a.add(0);
}
socket=new Socket("127.0.0.1", SocketServer.port);
reader =new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
for (int i = 0; i < 10; i++) {
if(i==4&&a.get(i)==0){
Thread.sleep(10000);
writer.println("确认号:"+"body" + i);
writer.flush();
String str=reader.readLine();
System.out.println(str);
a.set(i,1);
i--;
}
if(i==7&&a.get(i)==0){
writer.println("确认号:");
writer.flush();
String str=reader.readLine();
System.out.println(str);
a.set(i,1);
i--;
}
else {
writer.println("确认号:body" + i);
writer.flush();
String str=reader.readLine();
System.out.println(str);
a.set(i,1);
}
}
writer.println("end");
writer.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
reader.close();
writer.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
方法二
发送方的主要操作流程:
创建发送方的套接字,采用...端口号 ——> 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号 ——> 从此套接字发送数据报包 ——> 接收者接收并返回数据 ——> 关闭此数据报套接字。
接收方的主要操作流程:
接收操作并存储数据,并告诉发送者是否接收到。
Java代码实现:
package net;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class demo {
// 发送者--->客户端 客户端--->发送者
// 发送者发给客户端数据,客户端返回数据给发送者
public static void send() {
// 发送端
try {
// 创建发送方的套接字 对象 采用9004默认端口号
DatagramSocket socket = new DatagramSocket(9004);
// 发送的内容
String text = "hi xx!";
byte[] buf = text.getBytes();
// 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
DatagramPacket packet = new DatagramPacket(buf, buf.length,
InetAddress.getByName("172.22.67.6"), 9001);
// 从此套接字发送数据报包
socket.send(packet);
// 接收,接收者返回的数据
displayReciveInfo(socket);
// 关闭此数据报套接字。
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void recive() {
System.out.println("---recive---");
// 接收端
try {
//创建接收方的套接字 对象 并与send方法中DatagramPacket的ip地址与端口号一致
DatagramSocket socket = new DatagramSocket(9001,
InetAddress.getByName("172.22.67.6"));
//接收数据的buf数组并指定大小
byte[] buf = new byte[1024];
//创建接收数据包,存储在buf中
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//接收操作
socket.receive(packet);
byte data[] = packet.getData();// 接收的数据
InetAddress address = packet.getAddress();// 接收的地址
System.out.println("接收的文本:::" + new String(data));
System.out.println("接收的ip地址:::" + address.toString());
System.out.println("接收的端口::" + packet.getPort()); // 9004
// 告诉发送者 我接收完毕了
String temp = "我接收完毕了";
byte buffer[] = temp.getBytes();
//创建数据报,指定发送给 发送者的socket地址
DatagramPacket packet2 = new DatagramPacket(buffer, buffer.length,
packet.getSocketAddress());
//发送
socket.send(packet2);
//关闭
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 接收数据并打印出来
*/
public static void displayReciveInfo(DatagramSocket socket)
throws IOException {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
byte data[] = packet.getData();// 接收的数据
InetAddress address = packet.getAddress();// 接收的地址
System.out.println("接收的文本:::" + new String(data));
System.out.println("接收的ip地址:::" + address.toString());
System.out.println("接收的端口::" + packet.getPort()); // 9004
}
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
recive();
}
}.start();
new Thread() {
@Override
public void run() {
send();
}
}.start();
}
}