一、实验预热
1、请简单解释网络三要素都是什么,分别有什么作用。
IP地址:唯一标识网络上的每一台计算机
端口号:设备与外界通讯交流的出入口
协议:通信计算机双方必须共同遵从的一组约定
2、请描述Socket通信的一般流程。
首先Socket是网络驱动层提供给应用程序的接口,即通过Socket把数据从应用层封装到数据链路层,反之通过Socket可以解封我们的数据
3、请说明TCP和UDP传输的区别。
TCP:面向连接、传输可靠(保证数据正确性、保证数据顺序)、用于传输大量数据(流模式)、速度慢、建立连接需要开销较多(时间、系统资源)
UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快
二、实验内容
1、使用Socket编程实现基于TCP的多客户端用户登录。
代码:
服务器端:
package leif.tests.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) {
// 创建一个服务器端Socket,即ServerSocket
ServerSocket serverSocket = null;
try {
// 指定绑定的端口,并监听此端口
serverSocket = new ServerSocket(8888);
Socket socket = null;
// 记录客户端的数量
int count = 0;
System.out.println("服务器即将启动,等待客户端连接");
// 循环监听等待客户端连接
while (true) {
// 调用accept()方法开始监听,等待客户端连接
socket = serverSocket.accept();
// 创建一个新的线程
ServerThread serverThread = new ServerThread(socket);
// 启动线程
serverThread.start();
// 统计客户端的数量
count++;
System.out.println("客户端数量:" + count);
InetAddress inetAddress = socket.getInetAddress();
System.out.println("当前客户端IP:" + inetAddress.getHostAddress());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ServerThread extends Thread {
// 和本线程相关的Socket
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
// 线程执行的操作,响应客户端的请求
@Override
public void run() {
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
try {
// 获取一个输入流,并读取客户端的信息
inputStream = socket.getInputStream();
// 将字节流转化为字符流
inputStreamReader = new InputStreamReader(inputStream);
// 添加缓冲
bufferedReader = new BufferedReader(inputStreamReader);
String info = null;
// 循环读取数据
while ((info = bufferedReader.readLine()) != null) {
System.out.println("我是服务器,客户端说:" + info);
}
// 关闭输入流
socket.shutdownInput();
// 获取输出流,响应客户端的请求
outputStream = socket.getOutputStream();
// 将输出流包装为打印流
printWriter = new PrintWriter(outputStream);
printWriter.write("欢迎你");
// 将缓存输出
printWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (printWriter != null) {
printWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端1:
package leif.tests.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class Client1 {
public static void main(String[] args) {
Socket socket = null;
PrintWriter printWriter = null;
OutputStream outputStream = null;
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
// 创建客户端Socket,指定服务器端口号和地址
socket = new Socket("localhost", 8888);
// 获取输出流,向服务器发送信息
outputStream = socket.getOutputStream();
// 将输出流包装为打印流
printWriter = new PrintWriter(outputStream);
printWriter.write("用户名:lbc,密码:123");
printWriter.flush();
socket.shutdownOutput();
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
String info = null;
// 循环读取
while ((info = bufferedReader.readLine()) != null) {
System.out.println("我是客户端1,服务器说:" + info);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (printWriter != null) {
printWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端2:
package leif.tests.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class Client2 {
public static void main(String[] args) {
Socket socket = null;
PrintWriter printWriter = null;
OutputStream outputStream = null;
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
// 创建客户端Socket,指定服务器端口号和地址
socket = new Socket("localhost", 8888);
// 获取输出流,向服务器发送信息
outputStream = socket.getOutputStream();
// 将输出流包装为打印流
printWriter = new PrintWriter(outputStream);
printWriter.write("用户名:gll,密码:123");
printWriter.flush();
socket.shutdownOutput();
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
String info = null;
// 循环读取
while ((info = bufferedReader.readLine()) != null) {
System.out.println("我是客户端2,服务器说:" + info);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (printWriter != null) {
printWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
结果截图:
2、使用Socket实现基于UDP传输的客户咨询功能,要求接收方显示内容如下格式。
代码:
服务器端:
package leif.tests.socket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Scanner;
public class Server {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
Scanner scanner = null;
try {
// 接收数据
datagramSocket = new DatagramSocket(8648);
byte receiveData[] = new byte[4 * 1024];
// 两个参数:byte数组、数组长度
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
datagramSocket.receive(receivePacket);
// 三个参数:包、包的起始位置、包的大小
String result = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
System.out.println("客户端(" + receivePacket.getAddress().toString() + "):" + result);
// 发送数据
scanner = new Scanner(System.in);
System.out.print("我说:");
String string = scanner.next();
byte sendData[] = string.getBytes();
// 四个参数:byte数组、数组长度、发送的地址、发送的端口号
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, receivePacket.getAddress(), receivePacket.getPort());
datagramSocket.send(sendPacket);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
scanner.close();
}
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
}
客户端:
package leif.tests.socket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
Scanner scanner = null;
try {
datagramSocket = new DatagramSocket(5548);
InetAddress inetAddress = InetAddress.getLocalHost();
scanner = new Scanner(System.in);
System.out.print("我说:");
String string = scanner.next();
byte[] sendData = string.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, inetAddress, 8648);
datagramSocket.send(sendPacket);
byte receiveData[] = new byte[4 * 1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
datagramSocket.receive(receivePacket);
String result = new String(receivePacket.getData(), receivePacket.getOffset(), receivePacket.getLength());
System.out.println("服务器说:" + result);
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
scanner.close();
}
if (datagramSocket != null) {
datagramSocket.close();
}
}
}
}
结果截图: