概述
实验五 传输层通信的实现
- 一、 实验目的与要求
- 二、预习与准备
- 三、 实验内容
- 四、实验过程与结果记录
- 五、实验总结与体会
一、 实验目的与要求
1.理解传输层两个通信协议TCP与UDP
2.掌握简单UDP通信程序的编写
3.掌握简单TCP通信程序的编写
4.掌握简单多线程通信程序的编写
二、预习与准备
1.理解TCP与UDP协议的基本概念
2.java实现UDP和TCP的简单通信过程
三、 实验内容
1.InetAddress类的使用。
2.UDP通信的发送端和接收端程序的编写。
3.TCP通信的服务器端和客户端程序的编写。
四、实验过程与结果记录
1.InetAdderss类常用方法的使用
public class TestInetAdderss {
public static void main(String[] args) {
try {
//获取本机对应的InetAddress对象
InetAddress localAddress=InetAddress.getLocalHost();
//根据主机获得对应的InetAddress对象,参数host可以是IP地址或域名
InetAddress remoteAddress =InetAddress.getByName("www.baidu.com");
//打印本机IP地址
System.out.println("本机的IP地址:"+localAddress.getHostAddress());
//打印百度IP地址m
System.out.println("百度的IP地址:"+remoteAddress.getHostAddress());
//3秒是否可达
System.out.println("3秒是否可达:"+remoteAddress.isReachable(3000));
System.out.println("百度的主机名为:"+remoteAddress.getHostName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.UDP通信的发送端和接收端程序的编写
TalkReceive 类:
public class TalkReceive implements Runnable {
DatagramSocket socket = null;
private int port;
private String msgFrom;
public TalkReceive(int port,String msgFrom) {
this.port = port;
this.msgFrom = msgFrom;
try {
socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
//准备接收数据
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
socket.receive(packet);//阻塞式接受包裹
//断开连接 bye
byte[] data = packet.getData();
String receiveData = new String(data,0,data.length);
System.out.println();
System.out.println(msgFrom + ":" +receiveData);
if (receiveData.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
TalkSend 类:
public class TalkSend implements Runnable {
DatagramSocket socket = null;
BufferedReader reader = null;
private int fromPort;
private String toIP;
private int toPort;
public TalkSend(int fromPort, String toIP, int toPort) {
this.fromPort = fromPort;
this.toIP = toIP;
this.toPort = toPort;
try {
socket = new DatagramSocket(fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
try {
System.out.println();
System.out.print("我:");
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIP,this.toPort));
socket.send(packet);
if (data.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
UDPClient 类:
public class UDPClient {
public static void main(String[] args) {
//开启两个线程
new Thread(new TalkSend(6666,"localhost",9999)).start();
//接收来自8888服务器的信息
new Thread(new TalkReceive(8888,"服务端")).start();
}
}
3.TCP通信的服务器端和客户端程序的编写
TCP服务端:
SocketMode类
public class SocketMode {
private Socket socket = null;
private String clientName = null;
public SocketMode(Socket socket, String hostName) {
this.clientName = hostName;
this.socket = socket;
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
}
TalkServerReceiveHelper类:
public class TalkServerReceiveHelper extends Thread {
private SocketMode socketMode = null;
private TalkServerReceiveHelperListener listener = null;
// 是否关闭服务器端
// private boolean isShutDown = false;
public TalkServerReceiveHelper(SocketMode socketMode) {
this.socketMode = socketMode;
}
public void addTalkServerReceiveHelperListener(TalkServerReceiveHelperListener listener) {
this.listener = listener;
}
@Override
public void run() {
InputStream inputStream = null;
try {
while (true) {
// 获取当前的套接字对象
Socket socket = socketMode.getSocket();
//
inputStream = socket.getInputStream();
// 读取客户端发送过来的信息
byte[] buf = new byte[1024];
int len = inputStream.read(buf);
String str = new String(buf, 0, len);
if (str.equals("bye")) {
if (listener != null) {
listener.handleClientClose(socketMode);
}
break;
}
if (listener != null) {
TCPServerFrame.SM=socketMode;
listener.updateTalkMessage(socketMode.getClientName() + ": " + str);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
TalkServerReceiveHelperListener 类:
interface TalkServerReceiveHelperListener {
// 处理客户端关闭(或服务器端关闭)
void handleClientClose(SocketMode socketMode);
// 更新聊天信息
void updateTalkMessage(String message);
}
TCPServerFrame 类:
public class TCPServerFrame extends JFrame implements ActionListener, Runnable, TalkServerReceiveHelperListener {
//public static final SocketMode SM =null ;
// 发送信息的文本框
private JTextField tfSendMessage = new JTextField();
// 保存聊天信息
private JTextArea taTalkMessage = new JTextArea();
// 套接字地址对象
private InetSocketAddress inetSocketAddress = null;
// 是不是需要退出服务器端
private boolean isExitServer = false;
// 是不是服务器端主动关闭
private boolean isServerClose = false;
// private Socket socket = null;
private ServerSocket ss = null;
// 保存已连接的套接字
private List<Socket> socketList = new ArrayList<Socket>();
static SocketMode SM=null;
// 保存接受信息的线程
// private List<TalkServerReceiveHelper> receiveHelpers = new
// ArrayList<TalkServerReceiveHelper>();
public TCPServerFrame() {
super("聊天室-服务器程序");
}
public void initFrame() {
try {
inetSocketAddress = new InetSocketAddress(InetAddress.getLocalHost(), 2000);
} catch (UnknownHostException e) {
e.printStackTrace();
}
// 发送面板
JPanel sendPanel = new JPanel();
sendPanel.setPreferredSize(new Dimension(400, 70));
this.add(sendPanel, BorderLayout.NORTH);
// 发送标签
JLabel lblSend = new JLabel("发送:");
sendPanel.add(lblSend);
// 发送信息文本框
tfSendMessage.setPreferredSize(new Dimension(280, 30));
sendPanel.add(tfSendMessage);
// 发送按钮
JButton btnSend = new JButton("发送");
btnSend.setActionCommand("send");
btnSend.addActionListener(this);
sendPanel.add(btnSend);
//
String serverInfo = "服务器:" + inetSocketAddress.getAddress().getHostAddress() + " 端口号:" + inetSocketAddress.getPort();
JLabel lblServerInfo = new JLabel(serverInfo);
sendPanel.add(lblServerInfo);
//
taTalkMessage.setLineWrap(true);
JScrollPane spTalkMessage = new JScrollPane(taTalkMessage);
spTalkMessage.setPreferredSize(new Dimension(400, 200));
this.add(spTalkMessage);
// 按钮组面板
JPanel btnGroupPanel = new JPanel();
this.add(btnGroupPanel, BorderLayout.SOUTH);
//
String[] btnTexts = { "断开", "退出" };
String[] btnActionCommands = { "close", "exit" };
for (int i = 0; i < btnActionCommands.length; i++) {
JButton tempBtn = new JButton(btnTexts[i]);
tempBtn.setActionCommand(btnActionCommands[i]);
tempBtn.addActionListener(this);
btnGroupPanel.add(tempBtn);
}
//
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setBounds(100, 100, 440, 400);
this.setVisible(true);
}
public static void main(String[] args) {
TCPServerFrame tsf = new TCPServerFrame();
tsf.initFrame();
tsf.startThread();
}
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
if (actionCommand.equals("send")) {
String message = tfSendMessage.getText();
if (message.length() == 0) {
JOptionPane.showMessageDialog(this, "发送的信息不能为空!");
} else {
this.sendAllMessage(message, true);
}
} else if (actionCommand.equals("close") || actionCommand.equals("exit")) {
if (ss.isClosed()) {
// 如果退出,就关闭服务器端
if (actionCommand.equals("exit")) {
System.exit(0);
}
} else {
changeTalkMessage("正在断开与客户端的连接,请稍候");// 是不是服务器端主动关闭
isServerClose = true;
// 如果退出,就关闭服务器端
if (actionCommand.equals("exit")) {
isExitServer = true;
}
if (socketList.size() > 0) {
// 发送结束标识符
this.sendAllMessage("bye", false);
} else {
try {
ss.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
@Override
public void run() {
try {
// 创建服务器端套接字
ss = new ServerSocket();
// 绑定对应的ip地址和端口号
ss.bind(inetSocketAddress);
// 循环接收客户端的连接
int count = 1;
while (!isServerClose) {
// 监听客户端连接(线程会阻塞)
Socket socket = ss.accept();
// 添加已连接的套接字到集合中
socketList.add(socket);
// String client_name = "客户端" + count;
String client_name = "客户端" + socketList.size();
System.out.println(client_name + "已连接!");
// 组织信息
changeTalkMessage(client_name + "连接成功!");
// 初始化套接字模型类
SocketMode sm = new SocketMode(socket, client_name);
// 根据对话信息文本域和套接字列表以及套接字模型类初始化接收客户端线程,并启动线程
TalkServerReceiveHelper tsrh = new TalkServerReceiveHelper(sm);
tsrh.addTalkServerReceiveHelperListener(this);
tsrh.start();
// 把该线程添加到集合中
// receiveHelpers.add(tsrh);
// count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (SocketException e1) {
String message = e1.getMessage();
if (message.contains("socket closed")) {
changeTalkMessage("连接已关闭!");
} else {
e1.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ss != null) {
try {
if (!ss.isClosed()) {
ss.close();
}
changeTalkMessage("服务器已断开连接");
if (isExitServer) {
System.out.println("exit");
System.exit(0);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void startThread() {
Thread thread = new Thread(this);
thread.start();
}
//
private void changeTalkMessage(String message) {
String temp = taTalkMessage.getText();
if (temp.length() > 0) {
taTalkMessage.append("n");
}
taTalkMessage.append(message);
}
// 为每一个连接服务器端的客户端发送信息
public void sendAllMessage(String message, boolean isPrintMessage) {
//SocketMode socketMode = null;
//Socket socket = socketMode.getSocket();
// for (Socket socket : socketList) {
// }
//Socket socket=TalkServerReceiveHelper.socketMode.getSocket();
//Socket socket=socketList.get(socketList.size()-1);
// Socket socket = SM.getSocket();
sendMessage(message, SM.getSocket());
if (isPrintMessage) {
if (socketList.size() == 0) {
changeTalkMessage("没有客户端与服务器连接!");
} else {
// 只有发送成功才会显示信息
changeTalkMessage("我:" + message);
}
}
}
public void sendMessage(String message, Socket socket) {
if (!socket.isConnected() || socket.isClosed()) {
System.out.println("未连接和已关闭!");
return;
}
try {
byte[] datas = message.getBytes();
OutputStream os = socket.getOutputStream();
os.write(datas);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void handleClientClose(SocketMode socketMode) {
// TODO Auto-generated method stub
Socket socket = socketMode.getSocket();
if (!isServerClose) {
// 给客户端发送一个关闭标识符
this.sendMessage("bye", socket);
//
changeTalkMessage(socketMode.getClientName() + "已关闭连接!");
}
try {
//
socket.close();
// 关闭套接字之后,从集合中移除套接字对象
socketList.remove(socket);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void updateTalkMessage(String message) {
changeTalkMessage(message);
}
}
TCP客户端:
public class TCPClientFrame extends JFrame implements ActionListener, Runnable {
// 服务器ip地址的文本框
private JTextField tfServerIP = new JTextField();
// 服务器端口号的文本框
private JTextField tfServerPort = new JTextField();
// 保存聊天信息
private JTextArea taTalkMessage = new JTextArea();
// 发送信息的文本框
private JTextField tfSendMessage = new JTextField();
// 套接字地址对象
private InetSocketAddress inetSocketAddress = null;
// 是不是客户端主动退出
private boolean isClientClose = false;
// 初始化客户端套接字
private Socket socket = new Socket();
//标题
public TCPClientFrame() {
super("聊天室-客户端程序");
}
public void initFrame() {
// 连接的服务器地址
try {
inetSocketAddress = new InetSocketAddress(InetAddress.getLocalHost(), 2000);
} catch (UnknownHostException e) {
e.printStackTrace();
}
// 连接面板
JPanel connPanel = new JPanel();
connPanel.setPreferredSize(new Dimension(400, 70));
this.add(connPanel, BorderLayout.NORTH);
// 服务器标签
JLabel lblServer = new JLabel("服务器:");
connPanel.add(lblServer);
// ip地址文本框
tfServerIP.setPreferredSize(new Dimension(280, 30));
tfServerIP.setText(inetSocketAddress.getAddress().getHostAddress());
connPanel.add(tfServerIP);
// 连接按钮
JButton btnConn = new JButton("连接");
btnConn.setActionCommand("conn");
btnConn.addActionListener(this);
connPanel.add(btnConn);
// 端口号标签
JLabel lblPort = new JLabel("端口号:");
connPanel.add(lblPort);
// 端口号文本框
tfServerPort.setPreferredSize(new Dimension(280, 30));
tfServerPort.setText(inetSocketAddress.getPort() + "");
connPanel.add(tfServerPort);
// 发送按钮
JButton btnExit = new JButton("退出");
btnExit.setActionCommand("exit");
btnExit.addActionListener(this);
connPanel.add(btnExit);
//
String serverInfo = "服务器:" + inetSocketAddress.getHostName()
+ " 端口号:" + inetSocketAddress.getPort();
JLabel lblServerInfo = new JLabel(serverInfo);
connPanel.add(lblServerInfo);
//信息显示区域
taTalkMessage.setLineWrap(true);
JScrollPane spTalkMessage = new JScrollPane(taTalkMessage);
spTalkMessage.setPreferredSize(new Dimension(400, 200));
this.add(spTalkMessage);
// 发送面板
JPanel sendPanel = new JPanel();
sendPanel.setPreferredSize(new Dimension(400, 70));
this.add(sendPanel, BorderLayout.SOUTH);
// 发送标签
JLabel lblSend = new JLabel("发送:");
sendPanel.add(lblSend);
// 发送信息文本框
tfSendMessage.setPreferredSize(new Dimension(280, 30));
sendPanel.add(tfSendMessage);
// 发送按钮
JButton btnSend = new JButton("发送");
btnSend.setActionCommand("send");
btnSend.addActionListener(this);
sendPanel.add(btnSend);
//关闭窗口
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(100, 100, 440, 400);
this.setVisible(true);
}
//启动入口,初始化
public static void main(String[] args) {
TCPClientFrame tsf = new TCPClientFrame();
tsf.initFrame();
}
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
if (actionCommand.equals("send")) {
String message = tfSendMessage.getText();
if (message.length() == 0) {
JOptionPane.showMessageDialog(this, "发送的信息不能为空!");
} else {
sendMessage(message, true);
}
} else if (actionCommand.equals("conn")) {
try {
if (socket != null && socket.isConnected()) {
changeTalkMessage("服务器已连接成功!");
} else {
// 根据地址连接服务器
socket.connect(inetSocketAddress);
changeTalkMessage("服务器连接成功!");
// 开启读取客户端信息的线程
startRecThread();
}
} catch (IOException e1) {
e1.printStackTrace();
}
} else if (actionCommand.equals("exit")) {
changeTalkMessage("正在关闭连接,请稍候...");
isClientClose = true;
this.sendMessage("bye", false);
}
}
@Override
public void run() {
try {
// 循环接收服务器端的信息
while (true) {
InputStream inputStream = socket.getInputStream();
// 读取客户端发送过来的信息
byte[] buf = new byte[1024];
int len = inputStream.read(buf);
String str = new String(buf, 0, len);
System.out.println(str);
if (str.equals("bye")) {
if (!isClientClose) {
this.sendMessage("bye", false);
// 显示到文本域中
changeTalkMessage("服务器已断开连接!");
}
break;
}
// 显示到文本域中
changeTalkMessage("服务器: " + str);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
changeTalkMessage("客户端与服务器已断开连接!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//线程启动
private void startRecThread() {
Thread thread = new Thread(this);
thread.start();
}
//信息发送逻辑
private void sendMessage(String message, boolean isPrintMessage) {
if (socket.isClosed() || !socket.isConnected()) {
changeTalkMessage("客户端与服务器未连接或已关闭!");
return;
}
// 发送信息给服务器端
byte[] datas = message.getBytes();
try {
OutputStream os = socket.getOutputStream();
os.write(datas);
if (isPrintMessage) {
// 只有发送成功才会显示信息
changeTalkMessage("我:" + message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//显示到聊天界面的信息
private void changeTalkMessage(String message) {
String temp = taTalkMessage.getText();
if (temp.length() == 0) {
taTalkMessage.append(message);
} else {
taTalkMessage.append("n" + message);
}
}
}
五、实验总结与体会
UDP是无连接的协议,它以数据报作为数据传输的载体。数据报是一个在网络上发送的独立信息,它的到达、到达时间以及内容本身等都不能得到保证,每个DatagramSocket与一个本地地址,包括本地主机的IP地址和本地UDP端口绑定,每个DatagramSocket可以把UDP数据报发送给任意一个远程DatagramSocket,也可以接收来自任意一个远程DatagramSocket的UDP数据报。在UDP数据报中包含了目的地址的信息,DatagramSocket根据该信息把数据报发送到目的地。TCP是基于连接的协议,在正式收发数据前,必须和对方建立可靠的连接。TCP能为应用提供可靠的通信连接,使一台计算机发出的字节流无差错地发往网络上的其他计算机,对可靠性要求很高的数据通信系统往往使用TCP传输数据。
最后
以上就是粗心航空为你收集整理的实验五:传输层通信的实现一、 实验目的与要求二、预习与准备三、 实验内容四、实验过程与结果记录五、实验总结与体会的全部内容,希望文章能够帮你解决实验五:传输层通信的实现一、 实验目的与要求二、预习与准备三、 实验内容四、实验过程与结果记录五、实验总结与体会所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复