就目前我们做的c/s的简单交互而言主要用到了三个类:客户端线程类ClientThread 、 服务端监听类ChatServer 、 服务端线程类ChatThread。
简单理解:通过socket建立客户端与服务器的连接,在客户端和服务器分别用输入输出流来获得和写出消息,通过消息的传递达到交互的目的。
(ps: socket 实现客户端套接字 套接字是两台机器间通信的端点)
打开输入输出流(用字符流封装) InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); //将字节流转成字符流 reader = new BufferedReader(new InputStreamReader(in, "GB2312")); writer = new BufferedWriter(new OutputStreamWriter(out, "GB2312")); //读消息(线程循环读取) while(line != null){ line = reader.readLine(); } //发送消息 writer.write(msg); writer.flush();
客户端: 登陆界面类LoginUI 、 客户消息处理线程类ClientThread 、 聊天界面类ClientUI。
(1)登陆界面:主要是用来创建一个登陆的窗口,获得用户名以及密码
package 1; /** * (1) */ import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPasswordField; import javax.swing.JTextField; public class LoginUI extends JFrame{ private ClientThread ct; //入口函数 public static void main(String args[]){ LoginUI loginUI = new LoginUI(); loginUI.init(); } public void init(){ //创建一个登陆界面 this.setTitle("登陆界面"); this.setSize(200,200); this.setResizable(false); this.setDefaultCloseOperation(3); this.setLayout(new FlowLayout()); //创建标签 JLabel jb1 = new JLabel("用户名:"); this.add(jb1); //创建文本输入框 final JTextField username = new JTextField(10); this.add(username); JLabel jb2 = new JLabel("密 码:"); this.add(jb2); final JPasswordField passwd = new JPasswordField(10); this.add(passwd); //创建一个按钮对象 JButton jb3 = new JButton("登陆"); this.add(jb3); jb3.setActionCommand("login"); //给按钮添加监听器(内部类) jb3.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { //创建一个用户线程,在构造函数中传入界面对象(LoginUI.this)!!!!!!!!!!!!! 、ip、端口号、用户名、密码 ct = new ClientThread(LoginUI.this,"127.0.0.1",8008,username.getText(),passwd.getText()); //启动线程 Thread th = new Thread(ct); th.start(); } }); this.setVisible(true); } public void LoginResult(boolean result){ if(result == false){ //JOptionPane 有助于方便地弹出要求用户提供值或向其发出通知的标准对话框 (静态方法直接用类名调用) JOptionPane.showMessageDialog(this,"登陆失败!!哈哈哈哈。。。"); }else{ //登陆界面消失 this.dispose(); //创建一个聊天窗口 ClientUI ui = new ClientUI(ct); ui.init(); //将窗口作为参数传给用户处理线程 ct.setClientUI(ui); } } }
(2)线程类:将登陆结果返回给登陆界面、将服务器传送来的消息发给聊天界面对象
package 1; /** * 用户登陆处理线程 (2) */ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; import javax.swing.JFrame; public class ClientThread extends JFrame implements Runnable{ private LoginUI loginUI; private String ip; private int port; private String username; private String passwd; private ClientUI ui; private Socket socket; private BufferedWriter writer; private BufferedReader reader; private boolean runFlag = true; private boolean isLogin = false; //重载构造函数 public ClientThread(LoginUI loginUI,String ip,int port,String username,String passwd){ this.loginUI = loginUI; this.ip = ip; this.port = port; this.username = username; this.passwd = passwd; } //得到用户聊天界面对象 public void setClientUI(ClientUI ui){ this.ui = ui; } public boolean connectServer(){ try { //创建一个套接字 socket = new Socket(ip,port); //得到输入输出流对象 InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); //将字节流转成字符流 reader = new BufferedReader(new InputStreamReader(in, "GB2312")); writer = new BufferedWriter(new OutputStreamWriter(out, "GB2312")); return true; } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return false; } public void run(){ if(connectServer() == false){ System.out.println("登陆服务器失败!"); return; } login(); if(isLogin == false){ return; } String msg; try { //通过读入流获得消息 msg = reader.readLine(); while(runFlag && msg != null){ //将消息发送给聊天界面 ui.onMsg(msg); msg = reader.readLine(); } } catch (IOException e) { e.printStackTrace(); } System.out.println("ClientThread退出来了"); } public void sendMsg(String msg){ try { writer.write(msg+"\r\n"); writer.flush(); } catch (IOException e) { e.printStackTrace(); } } public void login(){ try { writer.write(username+"\r\n"); writer.write(passwd+"\r\n"); writer.flush(); String result = reader.readLine(); if("LoginOK".equals(result)){ System.out.println("登陆成功!"); isLogin = true; //创建一个新的聊天界面 loginUI.LoginResult(true); }else{ System.out.println(result); //弹出一个窗口显示登陆失败了 loginUI.LoginResult(false); } } catch (IOException e) { e.printStackTrace(); } } }
(3)聊天界面类:将消息显示在指定区域。
package 1; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JTextArea; public class ClientUI extends JFrame{ //声明一个线程 private ClientThread ct; public ClientUI(ClientThread ct){ this.ct = ct; } //创建一个指定行列的空文本域 “聊区” JTextArea logArea = new JTextArea(13,40); public void init(){ //创建聊天窗口 this.setTitle("聊吧"); this.setSize(500,400); this.setResizable(false); this.setDefaultCloseOperation(3); this.setLayout(new FlowLayout()); this.add(logArea); //创建一个指定行列的文本域 “发送消息区” final JTextArea sendMsg = new JTextArea(4,40); this.add(sendMsg); //创建一个发送按钮 JButton jb1 = new JButton("发送"); this.add(jb1); jb1.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { //发送文本区的内容 String msg = sendMsg.getText().toString(); //线程将消息发送过来 ct.sendMsg(msg); //将发送区清空 sendMsg.setText(""); } }); this.setVisible(true); } //接受服务器发送过来的消息 public void onMsg(String msg ){ //将消息显示在“聊吧”界面的聊天区 logArea.setText(logArea.getText()+msg+"\r\n"); } }
服务端: 服务端监听类ChatServer 、 服务端线程类ChatThread 、用户存储队列ChatTools、用户数据类DateTools。
(1)监听类的作用:监听端口 (监听一个端口号,等待用户的访和 创建一个服务端线程对象 。
package 1; /** * (1) */ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class ChatServer { public static void main(String[] args) { new ChatServer().setupServer(8008); } public void setupServer(int port) { try { //监听一个端口号码,等待用户的访问 ServerSocket ss = new ServerSocket(port); //循环等待客户端的访问 while(true){ //得到socket Socket socket = ss.accept(); //将socket传给服务端线程进行处理 ChatThread ct = new ChatThread(socket); //启动线程 ct.start(); } } catch (IOException e) { e.printStackTrace(); } } }
(2)线程类的作用:打开输入输出流(用字符流封装) 读消息(线程循环读取)、 处理消息、 发送消息给登录界面(不需要线程)、创建一个队列保存所有用户信息 。
package 1; /** * (2) */ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; public class ChatThread extends Thread { private Socket socket; private String username; private boolean isLogin = false; private BufferedWriter writer; private BufferedReader reader; public ChatThread(Socket socket){ this.socket = socket; } public void run() { try { InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); //将字节流转成字符流 reader = new BufferedReader(new InputStreamReader(in, "GB2312")); writer = new BufferedWriter(new OutputStreamWriter(out, "GB2312")); login(); //将登录成功的用户添加到在线用户队列 ChatTools.addClient(this); String line = reader.readLine(); while(line != null){ ChatTools.castMsg(username +"说:"+line); line = reader.readLine(); } close(); //ChatTools.castMsg(username +"走了"); } catch (Exception e) { close(); e.printStackTrace(); } } private void login() throws IOException { String msg = null; while(isLogin == false){ String username = reader.readLine(); String passwd = reader.readLine(); //从数据库中取密码 String passwd2 = DateTools.getPasswd(username); //如果为null,说明数据库里面没有该用户 if(passwd2 == null){ msg = "用户不存在\r\n"; writer.write(msg); writer.flush(); } else { if(passwd2.equals(passwd)){ isLogin = true; this.username = username; } } if(isLogin == false){ msg = "密码错误!\r\n"; writer.write(msg); writer.flush(); } } //给用户登陆界面一个信号,决定其下一步是弹出“登录失败”还是一个新的聊天窗口 msg = "LoginOK\r\n"; writer.write(msg); writer.flush(); } public void sendMsg(String msg) { try { writer.write(msg); writer.flush(); } catch (IOException e) { e.printStackTrace(); } } public String getUsername() { return username; } public void close() { try { ChatTools.remove(this); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
(4)用户存储队列ChatTools :将登录成功的用户加入到队列中(代码略)
(5)用户数据类DateTools : 创建一个哈希表(key,value),将指定值存入。(代码略)
相关推荐
下面将详细介绍Java Socket在C/S通信中的应用,以及如何构建这样的系统。 一、Java Socket基础 1. Socket概念:Socket在计算机网络中是一种进程间通信机制,它提供了一种在网络上的两个进程之间建立和维护连接的...
1. **Socket编程**:Java的`java.net.Socket`和`ServerSocket`类是实现C/S通信的基础。服务器端创建`ServerSocket`监听特定端口,等待客户端的连接请求;客户端使用`Socket`连接到服务器,建立通信通道。 2. **多...
本项目名为"vb 编写的c/s简单通信程序",其核心是实现基本的TCP(Transmission Control Protocol)网络通信,这是网络通信的基础。 TCP是一种面向连接的、可靠的传输协议,它确保了数据的完整性和顺序,适合于需要...
在" C/S构架的网络通信程序 "这个主题中,我们将深入探讨C#语言下如何利用Socket库来实现基于TCP协议的可靠网络通信。 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的...
C/S架构指的是客户端(Client)与服务器(Server)之间的架构模式,这是一种分布式软件架构,其中客户端负责提供用户交互界面以及执行一部分业务逻辑,而服务器端则主要负责数据存储管理和复杂业务逻辑处理。 - **特点*...
C/S(Client/Server)架构是一种常见的软件系统架构模式,其中客户端(Client)与服务器端(Server)通过网络进行通信,以实现数据的交互和处理。在这个架构中,客户端是用户直接操作的部分,负责用户界面的展示和...
在这个"Netty框架各种通信C/S端"的资源中,包含了使用Netty实现客户端(Client)和服务器(Server)通信的实例。 1. **TCP通信**: TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的...
C/S(Client/Server)模式是一种常见的软件架构模式,它将应用逻辑分为客户端(Client)和服务器端(Server)两部分,客户端负责用户交互,服务器端则处理数据存储和管理。在这个场景中,我们讨论的是一个基于Java...
C/S通信,即客户端/服务器通信,是网络编程中的基本模式,通常用于构建分布式系统。在这个场景下,C++可以用来编写服务器和客户端应用程序,实现数据的交互。 在C/S通信中,服务器端负责监听客户端的连接请求,并对...
在"基于TCP的C/S简单Swing通信"项目中,Swing被用来构建客户端的用户界面,用户可以通过界面发送和接收数据。TCP协议则用于客户端和服务器之间的数据传输。Swing组件如按钮、文本框等可以与TCP连接事件绑定,当用户...
三层架构是一种常见的软件设计模式,尤其在B/S(Browser/Server)和C/S(Client/Server)架构中广泛应用。这种架构将应用分为三个主要部分:表现层(Presentation Layer)、业务逻辑层(Business Logic Layer)和...
C/S 结构软件测试的优点是可以更好地测试客户端和服务器端的交互,发现问题的原因和解决方法。但是,C/S 结构软件测试也存在一些缺点,例如需要多台机器和网络环境,测试过程复杂。 二、B/S 结构软件测试 B/S 结构...
在C/S模式下,客户端负责用户交互,而服务器端则处理客户端请求并提供服务。本主题将深入探讨如何利用C#语言在.NET框架下实现C/S模式的网络通信。 首先,我们要理解C#中的网络通信基础。C#提供了丰富的类库,如...
在C/S模式下,客户端主要负责数据展示、用户交互和部分简单计算,而服务器端则承担数据存储、复杂业务逻辑处理以及多客户端同步协调的任务。这样的设计确保了系统的稳定性和数据的安全性,同时,由于客户端与服务器...
在本文中,我们将深入探讨如何使用Qt Creator在Linux平台上编写基于C/C++的局域网通信(C/S)程序。Qt Creator是一个强大的集成开发环境,适用于C++编程,支持多种平台,包括Linux。我们将主要关注以下几个关键知识...
C/S架构的优势在于交互性强,用户体验良好,但缺点是需要为每个客户端单独安装和维护软件,更新迭代成本较高。 B/S架构,又称为浏览器-服务器架构,是基于Web的多层架构。用户只需通过浏览器访问服务器上的Web应用...
### C/S与B/S并用的高校教务管理系统研究与设计 #### 一、引言 随着信息技术的快速发展,特别是互联网技术的普及,各种计算模式也在不断地演变和发展。其中,客户端/服务器(Client/Server,简称C/S)模式与浏览器/...
在IT行业中,C/S(Client/Server)架构是一种常见的软件设计模式,它将应用程序的用户界面部分和数据处理部分分离,使得客户端可以提供交互式的用户体验,而服务器端负责处理复杂的业务逻辑和数据管理。HTML...
### B/S与C/S框架的区别 #### 一、概述 在信息技术领域中,B/S(Browser/Server,浏览器/服务器)架构与C/S(Client/Server,客户端/服务器)架构是两种非常重要的软件系统设计模式。这两种模式在实际应用中各有...
- **安全性对比**:C/S架构下,由于客户端和服务器之间直接通信,每一台客户端都可能成为安全隐患,尤其是在网络环境中;而B/S架构中,所有数据处理都在服务器端完成,客户端只负责展示和用户交互,从而在一定程度上...