资源描述
1. 实验设计目的:
(1)掌握类的定义和使用;
(2)掌握对象的定义;
(3)掌握线程的使用。
2. 实验设计内容:
设计一个类似qq群聊的聊天软件
3. 技术要点:
客户端和服务器端的开发,数据库的链接与使用
4. 实验条件:
(1)主要设备: 586或更高机型,256MB或更高的内存,40G或更大的硬盘。
(2)主要软件:
①操作系统可为Windows9X、WinMe、Win2000或更高版本等;
②开发环境为jdk或者jcreator。
(3)参考书目:
①尹继平,张帆.java范例大全.机械工业出版社
②施霞萍.java程序设计教程.机械工业出版社
5. 实验方法与步骤:
这个软件从0.1到1.3一共13个版本。0.1到0.4版本为客户端界面设计,第0.5到1.2版本为服务器端设计以及客户端与服务器端通信连接的设计实现。1.3版为完善之前版本的缺陷并添加登陆界面。
最终版本1.3版中一共三个类(如图一所示)
源代码如下:
//客户端
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import .*;
import java.io.*;
public class ChatClient extends Frame {
Socket s = null;
DataOutputStream dos = null;
DataInputStream dis = null;
private boolean bConnected = false;
private static final long serialVersionUID = 1L;
TextField tfTxt = new TextField();
TextArea taContent = new TextArea();
public static void main(String[] args) {
// TODO Auto-generated method stub
new Login();
}
public void launchFrame() {
setLocation(400, 300);
this.setSize(300, 300);
add(tfTxt, BorderLayout.SOUTH);
add(taContent, BorderLayout.NORTH);
pack();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
disconnect();
System.exit(0);
}
});
tfTxt.addActionListener(new TFListener());
setVisible(true);
connect();
new Thread(new RecvThead()).start();
}
public void connect() {
try {
s = new Socket("127.0.0.1", 8888);
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
System.out.print("lian jie shang le ");
bConnected = true;
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void disconnect() {
try {
dos.close();
s.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class TFListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
String ip = null;
String address= null;
InetAddress addr;
try {
addr = InetAddress.getLocalHost();
ip=addr.getHostAddress().toString();//获得本机IP
address=addr.getHostName().toString();//获得本机名称
} catch (UnknownHostException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
String str =address+ip+"\n"+ tfTxt.getText().trim();
// taContent.setText(str);
tfTxt.setText("");
try {
// DataOutputStream dos=new
// DataOutputStream(s.getOutputStream());
dos.writeUTF(str);
dos.flush();
// dos.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
private class RecvThead implements Runnable {
@Override
public void run() {
try {
while (bConnected) {
String str;
str = dis.readUTF();
taContent.setText(taContent.getText()+str+'\n');
System.out.print(str);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//服务器端
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.*;
import .*;
import java.util.*;
public class ChatServer {
boolean started = false;
ServerSocket ss = null;
List<Client>clients=new ArrayList<Client>();
public static void main(String[] args) {
// Socket s=null;
// DataInputStream dis =null;
new ChatServer().start();
}
public void start() {
try {
ss = new ServerSocket(8888);
started = true;
} catch (BindException e) {
System.out.print("端口使用中!\n");
System.out.print("请关闭相关程序重新运行程序!\n");
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
try {
while (started) {
// oolean bConnected=false;
// s=ss.accept();
Socket s = ss.accept();
Client c = new Client(s);
System.out.print("已连接!\n");
new Thread(c).start();
clients.add(c);
}
// dis.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
class Client implements Runnable {
private Socket s;
private DataInputStream dis = null;
private DataOutputStream dos=null;
private boolean bConnected = false;
public Client(Socket s) {
this.s = s;
try {
dis = new DataInputStream(s.getInputStream());
dos =new DataOutputStream(s.getOutputStream());
bConnected = true;
} catch (IOException e) {
e.printStackTrace();
}
}
public void send(String str){
try {
dos.writeUTF(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run() {
try {
while (bConnected) {
String str = dis.readUTF();
System.out.print(str + "\n");
for (int i=0;i<clients.size();i++){
Client c=clients.get(i);
c.send(str);
}
}
} catch (EOFException e) {
System.out.print("客户端断开连接!\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (dis != null)
dis.close();
if (dos != null)
dos.close();
// if(s!=null)s.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
//客户端登陆
* To change this template, choose Tools | Templates
import javax.swing.*;
/**
*
* @author Administrator
*/
public class Login extends JFrame implements ActionListener{
JPanel pnlLogin;
JLabel lblUserName,lblPassword,P;
JButton btnLogin,btnExit;
JTextField txtUserName,txtlbldl;
JPasswordField pwdPassword;
Dimension dsSize;
Toolkit toolkit=Toolkit.getDefaultToolkit();
public Login(){
super("登陆");
pnlLogin=new JPanel();
this.getContentPane().add(pnlLogin);
pnlLogin.setLayout(null);
lblUserName=new JLabel("用户名(U):");
lblPassword=new JLabel("密码:");
txtUserName=new JTextField(20);
pwdPassword=new JPasswordField(30);
btnLogin=new JButton("登录(L)");
btnLogin.setMnemonic('L');
btnExit=new JButton("退出(X)");
btnExit.setToolTipText("退出系统");
btnExit.setMnemonic('X');
btnLogin.addActionListener(this);
btnExit.addActionListener(this);
// P.setBounds(0,0,315,120);
// pnlLogin.add(P);
pnlLogin.setBackground(Color.WHITE);
lblUserName.setBounds(10,125,90,25);
txtUserName.setBounds(120,125,180,25);
lblPassword.setBounds(10,155,90,25);
pwdPassword.setBounds(120,155,180,25);
btnLogin.setBounds(20,185,80,25);
btnExit.setBounds(220,185,80,25);
lblUserName.setForeground(Color.BLACK);
lblUserName.setBackground(Color.WHITE);
lblPassword.setForeground(Color.BLACK);
lblPassword.setBackground(Color.WHITE);
pnlLogin.add(lblUserName);
pnlLogin.add(txtUserName);
pnlLogin.add(lblPassword);
pnlLogin.add(pwdPassword);
pnlLogin.add(btnLogin);
pnlLogin.add(btnExit);
setResizable(false);
setSize(315,245);
setVisible(true);
dsSize=toolkit.getScreenSize();
setLocation(dsSize.width/2-this.getWidth()/2,dsSize.height/2-this.getHeight()/2);
}
@Override
public void actionPerformed(ActionEvent ae){
if(ae.getSource()==btnLogin)
{
String jusername =txtUserName.getText().trim();
char[] s = pwdPassword.getPassword();
String jpassword = new String(s);
if (jusername.equals("") || jpassword.equals(""))
{
JOptionPane.showMessageDialog(this, "对不起,请输入用户名或密码.", "错误!",JOptionPane.ERROR_MESSAGE);
}
else
{
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
//System.out.println("加载驱动程序成功");
}
catch(Exception e)
{
System.out.println("无法加载驱动程序");
}
try{
String url = "jdbc:sqlserver://localhost:1433;DatabaseName=login";
// pubs为你的数据库的
String user = "";//用自己的数据库登录账户和密码
String password = "";//
Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
// if(jusername.length()<30){
// for(int i=0;i<27;i++)
// jusername=jusername+" ";
// }
ResultSet rs = stmt.executeQuery( "select username,password from login_user where username='"+jusername+"'");
if (rs.next())
{
String a=rs.getString("password").trim();
if (a.equals(jpassword))
{
JOptionPane.showMessageDialog(null, "登陆成功");
new ChatClient().launchFrame();
super.setVisible(false);
}
else {
JOptionPane.showMessageDialog(this, "对不起,密码错误,请重新输入","登陆失败", JOptionPane.ERROR_MESSAGE);
}
}
else {
JOptionPane.showMessageDialog(this, "用户名不存在,请重新输入", "错误!",JOptionPane.ERROR_MESSAGE);
}
rs.close();
stmt.close();
}
catch(SQLException e)
{
System.out.println("SQL异常");
}
}
}
if(ae.getSource()==btnExit)
System.exit(0);
}
public static void main(String args[]){
Login d5_3 = new Login();
}
}
程序运行截图
登陆界面
登陆失败
登陆成功
多个客户端登陆聊天,一个发起聊天在线的全部能收到
6. 实验总结:
这个实验的主要技术是包中的是socket使用。要想开发一个聊天系统一定要了解信息在网络中首发传递的过程,学会最基本的socket的使用。技术难点之一是服务器的设计,要解决怎么是服务器能连接多个客户端,我这使用的是多线程技术,难点二是数据库的使用,怎么连接,怎么读取添加数据。
程序的不足:(1)数据库设计简单,数据库只使用了一个用户表,在登陆聊天的时候只是读取登陆者身份,进行验证没有注册。
(2)没有重复登陆的检验
(3)这个如今仅能显示登陆者的ip不能反映用户信息、
(4)信息的传递没有进行加密,信息不安全
程序不足的解决方法:(1)对不足(1)的解决方法是添加一个注册界面,用于对用户表用户的添加。
(2)对重复登陆的检验的解决办法是在数据库中添加一个登陆状态的校验值,默认为0,登陆后改为1;当此值为1时禁止在登陆
(3)对于不能显示登陆用户的解决方法是从数据库中读取用户名
(4)信息未加密的解决办法是添加一个加密解密的类对数据进行加解密
这个实验是我懂得了设计实验的基本方法,从一个简单版本,一步步的添加完善功能。正所谓罗马不是一天建立起来的,进行软件开发也是一样,要从简单的模型开始,一点点开发,发现问题解决为题将软件不断完善。
— 14 —
展开阅读全文