目录
1、实验要求
2、实验一
2.1、采用TCP协议实现一对一文件上传
2.2、采用UDP协议实现一对一文件上传
3、实验二
1.请分别采用TCP、UDP协议编程实现一对一的文件上传。
2.编写一对多的聊天程序,程序由服务器和客户端两部分构成,两部分的交互方式如下:
a.客户端发送命令:
b.客户端发送命令:
c.客户端发送命令:
d.服务器向指定客户端发送命令:
e.客户端发送命令:
程序可以采用GUI,也可采用命令行的方式。
1.请分别采用TCP、UDP协议编程实现一对一的文件上传。
在学习TCP\IP结构的时候,提到过传输层的两个重要的高级协议,他们分别是TCP和UDP,其中TCP的是传输控制协议、UDP是用户数据报协议。
TCP协议是面向连接的通信协议、即在传输数据前要现在发送端和接收端建立逻辑连接之后才能传输数据,保证了两个计算机之间可以没有差错的进行数据传输。要经过三次握手、第一次握手时客户端向服务端发出连接请求、等待服务器的确认,第二次握手是服务器向客户端返回一个响应去通知客户端已经收到了连接请求,第三次握手是客户端再向服务端发送确认连接的消息,由此看见利用TCP协议传输文件的速度较慢、但是传送的数据还是可靠的。
UDP协议是一种无连接的协议,当文件发送后,无法知道其发送的文件是否安全稳定完整的达到。可以形象的比喻为往杯子里倒水,倒水了但不一定完整倒入、可能没倒入水、可能倒入一点水、可能全倒入水了。使用UDP协议、消耗资源小、通信效率高、延迟小、通常也会被用在音频和视频等的传播,但是传送重要数据的时候不建议使用UDP协议。
用户端:
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
//1.创建一个socket连接
Socket socket = new Socket(InetAddress.getByName("localhost"), 9000);
//2.创建一个输出流
OutputStream os = socket.getOutputStream();
//3.文件流,读入文件
FileInputStream fis = new FileInputStream(new File("E:\\学习\\代码\\AdvancedJAVA\\src\\homework5\\experiment1\\header-logo.png"));
//4.写出文件
byte[] buffer = new byte[1024];
int lens;
while ((lens = fis.read(buffer)) != -1) {
os.write(buffer, 0, lens);
}
//通知服务器,我已经传输完了,已经结束了。
socket.shutdownOutput();//我已经传输完了
// 确定服务器接收完毕,才能够断开连接
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[1024];
int lens2;
while ((lens2 = is.read(buffer2)) != -1) {
baos.write(buffer2, 0, lens2);
}
System.out.println(baos.toString());
//5.关闭资源
baos.close();
fis.close();
os.close();
socket.close();
}
}
服务端:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server {
public static void main(String[] args) throws IOException {
//1创建服务
ServerSocket serverSocket = new ServerSocket(9000);
//2监听客户端的连接
Socket socket = serverSocket.accept();//阻塞式监听,会一直等待客户端。
//3获取输入流
InputStream is = socket.getInputStream();
//4文件输出,管道输出流
FileOutputStream fos = new FileOutputStream(new File("receive.png"));
byte[] buffer = new byte[1024];
int lens;
while ((lens = is.read(buffer)) != -1) {
fos.write(buffer, 0, lens);
}
//通知客户端我接受完毕了
OutputStream os = socket.getOutputStream();
os.write("我接收完毕了,你可以断开了".getBytes(StandardCharsets.UTF_8));
//关闭资源
os.close();
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
发送:
import java.io.FileInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//不需要连接服务器
public class send {
public static void main(String[] args) throws Exception {
//1.建立一个socket
DatagramSocket socket = new DatagramSocket();
//2.建立一个包
//发送给谁
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9090;
FileInputStream fis = new FileInputStream("E:\\学习\\代码\\AdvancedJAVA\\src\\homework5\\experiment1\\2.png");
byte[] buffer = new byte[1024];
int lens;
String str = "";
while ((lens = fis.read(buffer)) != -1) {
str += new String(buffer, 0, lens);
}
buffer = str.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, localhost, port);
//3.发送包
socket.send(packet);
//关闭流
socket.close();
}
}
接收:
import java.io.FileOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class receive {
public static void main(String[] args) throws Exception {
//开放端口
DatagramSocket socket = new DatagramSocket(9090);
//接收数据(包)
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);//接收
socket.receive(packet);
//将得到的packet进行拆包
int len = packet.getLength();
byte[] data = packet.getData();
String str = new String(data, 0, len);
//利用FileOutputStream将数据写入到文件中
String targetPath = "E:\\学习\\代码\\AdvancedJAVA\\src\\homework5\\experiment1\\21.png";
FileOutputStream fos = new FileOutputStream(targetPath);
fos.write(str.getBytes());
//关闭相关流
System.out.println("文件上传完毕");
fos.close();
socket.close();
//关闭连接
socket.close();
}
}
2.编写一对多的聊天程序,程序由服务器和客户端两部分构成,两部分的交互方式如下:
a.客户端发送命令:
b.客户端发送命令:
c.客户端发送命令:
d.服务器向指定客户端发送命令:
e.客户端发送命令:
程序可以采用GUI,也可采用命令行的方式。
用户1:(有能力做GUI,这体现多个用户的话,多设计几个用户端就ok了)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class Client01 {
private static String user;
public static void main(String[] args) throws IOException {
System.out.println("————————欢迎来到xxx设计的聊天界面窗口————————");
Socket socket = new Socket(InetAddress.getByName("localhost"), 8888);
Scanner scanner = new Scanner(System.in);
while (true) {
InputStreamReader reader = new InputStreamReader(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(reader);
PrintWriter writer = new PrintWriter(socket.getOutputStream());
System.out.println("输入相应数字选择您要进行的操作");
System.out.println("1--注册用户");
System.out.println("2--登陆账户");
System.out.println("3--发送信息");
System.out.println("4--登出账户");
System.out.println("5--接收信息");
System.out.println("其他数字--退出系统");
int choice = scanner.nextInt();
String instruction = "";
if (choice == 1) {
System.out.print("请输入您想要注册的账户名称:");
String name = scanner.next();
instruction = " ";
writer.println(instruction);
writer.flush();
} else if (choice == 2) {
System.out.print("请输入您想要登录的账户名称:");
user = scanner.next();
instruction = " ";
writer.println(instruction);
writer.flush();
} else if (choice == 3) {
System.out.print("请输入您想要发送的用户名称:");
String toUser = scanner.next();
System.out.println(toUser);
System.out.println("你说:");
String message = scanner.next();
System.out.println(message);
instruction = "";
writer.println(instruction);
writer.flush();
} else if (choice == 4) {
System.out.print("请输入您想要登出的账户:");
String name = scanner.next();
instruction = " ";
writer.println(instruction);
writer.flush();
} else if (choice == 5) {
System.out.println("等待接受消息中...");
String response0 = bufferedReader.readLine();
String[] strings = response0.split("\"");
String fromUser = strings[7];
String message = strings[5];
System.out.println(fromUser + "说:" + message);
continue;
} else {
instruction = "";
writer.println(instruction);
writer.flush();
break;
}
String response = bufferedReader.readLine();
String[] strings = response.split("\"");
String command = strings[1];
String state = strings[3];
if (command.equals("register")) {
if (state.equals("ok")) {
System.out.println("注册成功!");
} else {
System.out.println("已存在该用户,注册失败请重新注册");
}
} else if (command.equals("login")) {
if (state.equals("ok")) {
System.out.println("登陆成功!");
} else {
System.out.println("该用户不存在(或重复登陆),请重新登录");
}
} else if (command.equals("logout")) {
if (state.equals("ok")) {
System.out.println("成功退出账户!");
} else {
System.out.println("该账户不存在(未登录),请重试");
}
} else if (command.equals("message")) {
if (state.equals("ok")) {
System.out.println("成功发送消息!");
} else {
System.out.println("您对话的用户不存在(未登录),请重试");
}
}
}
socket.close();
System.out.println("---成功退出系统---");
}
}
Server:(考虑到HashMap是线程不安全的,所以将其更换为Hashtable)
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;
public class Server {
//利用图存储用户的登录状态
static Hashtable user = new Hashtable<>();
//利用图存储用户登录的客户端
static Hashtable client = new Hashtable<>();
public static void main(String[] args) throws IOException {
//服务器在本机8888端口进行监听,等待连接
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务器在本机8888端口进行监听,等待连接...");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("成功监听到客户端" + socket.getPort());
SocketHandler handler = new SocketHandler(socket);
Thread thread = new Thread(handler);
thread.start();
}
}
}
SocketHandler:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class SocketHandler implements Runnable {
private Socket socket;
public SocketHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStreamReader reader = new InputStreamReader(socket.getInputStream());
BufferedReader bufferedReader = new BufferedReader(reader);
PrintWriter writer = new PrintWriter(socket.getOutputStream());
PrintWriter toWriter = null;
while (true) {
String request = bufferedReader.readLine();
if (request == null) {
continue;
}
String line = "";
String[] strings = request.split("\"");
String name = strings[1];
if (request.startsWith(" ";
} else {
line = " ";
}
writer.println(line);
writer.flush();
} else if (request.startsWith(" ";
Server.user.put(name, true);
Server.client.put(name, writer);
} else {
line = "";
}
writer.println(line);
writer.flush();
} else if (request.startsWith(" ";
toWriter.println(line);
toWriter.flush();
} else {
line = " ";
}
writer.println(line);
writer.flush();
} else if (request.startsWith(" ";
} else {
line = " ";
}
writer.println(line);
writer.flush();
break;
}
}
//关闭相关流
writer.close();
toWriter.close();
bufferedReader.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}