JAVA入门到精通-网络编程补充和QQ案例
------------------------------------------------------
补充讲解:
如何在网络间传递对象?
[MyServer.java]服务器源代码
package com.test.server;import java.io.ObjectInputStream;import java.net.ServerSocket;import java.net.Socket;import com.common.User; public class MyServer { ServerSocket ss; Socket s; ObjectInputStream ois; public static void main(String[] args) { new MyServer(); } //构造函数 public MyServer(){ try { ss=new ServerSocket(3456); s=ss.accept(); //以对象流的方式读取(假设客户端发送的是User的一个对象) ois=new ObjectInputStream(s.getInputStream()); User u=(User)ois.readObject(); //输出 System.out.println(u.getName()+"\t"+u.getPasswd()); } catch (Exception e) { e.printStackTrace(); }finally{ try { if(ois!=null) ois.close(); if(s!=null) s.close(); if(ss!=null) ss.close(); } catch (Exception e2) { e2.printStackTrace(); } } }}[User.java]服务端的公共服务
package com.common; import java.io.Serializable; public class User implements Serializable{ private String name; private String passwd; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; }}[MyClient.java]客户端源代码
package com.test.client; import java.io.ObjectOutputStream;import java.net.Socket;import com.common.User; public class MyClient { Socket s; ObjectOutputStream oos; public static void main(String[] args) { new MyClient(); } //构造函数 public MyClient(){ try { s=new Socket("127.0.0.1",3456); //通过ObjectOutputStream给服务器传送对象 oos=new ObjectOutputStream(s.getOutputStream()); User u=new User(); u.setName("张三"); u.setPasswd("123"); oos.writeObject(u); } catch (Exception e) { e.printStackTrace(); }finally{ try { if(oos!=null) oos.close(); if(s!=null) s.close(); } catch (Exception e2) { e2.printStackTrace(); } } }}[User.java]客户端的公共服务
package com.common; import java.io.Serializable;//通过io在网络上传送对象需要进行序列化Serializablepublic class User implements Serializable{ private String name; private String passwd; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; }}特别说明:
在java网络编程需要通过IO流实现对象的传递需要对,服务端和客户端定义相同的传递对对向方法,以达到实现对象的传递。同时需要对方法进行Serializable序列化,否则报错。
------------------------------
QQ案例
说明:该案例主讲内容:java网络编程、多线程、C/S数据交互
附源代码
注:代码分为Server部分与Client部分,由于此案例仅为对NET操作未使用数据库
Server部分包含的包有:
1、com.qq.server.view (服务端界面包)
1.1、QqServerFrame.java (服务端主页面)
2、com.qq.server.model (业务逻辑包)
2.1、MyQqServer.java (服务器验证客户信息)
2.2、QqServerUser.java (用于管理QQ用户信息[此包功能应为对数据库逻辑操作])(空)
2.3、SerConClientThread.java (服务器连接客户端线程)
2.4、ManageClientThrea.java (管理客户端连接线程)
3、com.qq.server.db (数据库操作包)
3.1、SqlHelper.java (对数据库的CURD操作)(空)
4、com.qq.server.tools (服务端工具包)(空)
5、com.qq.common (通用包)
5.1、Message.java (消息类)
5.2、MessageType.java (消息类型接口类)
5.3、User.java (用户信息类)
Client部分包含的包有:
1、com.qq.client.view (客户端界面包)
1.1、QqClientLogin.java (QQ登录界面)
1.2、QqFriendList.java (好友列表界面)
1.3、QqChat.java (聊天界面)
2、com.qq.client.model (客户端业务逻辑包)
2.1、QqClienConServer.java (客户端连接服务端的后台用于与服务端数据交互)
2.2、QqClientUser.java (客户端用户操作逻辑类)
3、com.qq.client.tools (原应为客户端工具包,现为处理与服务端的线程包)
3.1、ClientConServerThread.java (客户端连接服务器线程类)
3.2、ManageClientConServerThread.java (管理C/S线程类)
3.3、ManageQqChat.java (管理聊天界面类)
3.4、ManageQqFriendList.java (管理好友列表类)
4、com.qq.common (通用包)
4.1、Message.java (消息类)
4.2、MessageType.java(消息类型类)
4.3、User.java (用户信息类)
注意:Server与Client中的com.qq.common通用包主要功能是统一保持客户端与服务端的用户及消息一致。
下见源代码:
Server端源代码:
com.qq.server.view
[QqServerFrame.java]
/** * 服务器端的控制界面 * 功能: * 1、完成启动、关闭服务器 * 2、管理及监控用户 */package com.qq.server.view; import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;import com.qq.server.model.MyQqServer; public class QqServerFrame extends JFrame implements ActionListener{ JPanel jp1; JButton jb1,jb2; public static void main(String []args){ new QqServerFrame(); } //构造函数 public QqServerFrame(){ jp1=new JPanel(); jb1=new JButton("启动服务器"); jb1.addActionListener(this); jb2=new JButton("关闭服务器"); jb2.addActionListener(this); jp1.add(jb1); jp1.add(jb2); this.add(jp1); this.setSize(500, 400); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==jb1){ new MyQqServer(); }else if(e.getSource()==jb2){ System.exit(0); } }}*******************************************************************************
com.qq.server.model
[MyQqServer.java]
/** * 这是QQ服务器,它在监听等待某个QQ客户端连接服务器 */package com.qq.server.model; import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.ServerSocket;import java.net.Socket;import com.qq.common.Message;import com.qq.common.User; public class MyQqServer { BufferedReader br; public MyQqServer(){ try { System.out.println("服务器在监听9999端口..."); //在9999端口监听 ServerSocket ss=new ServerSocket(9999); //等待连接 while(true){ Socket s=ss.accept(); //接收客户端发来的信息 ObjectInputStream ois=new ObjectInputStream(s.getInputStream()); User u=(User)ois.readObject(); Message m=new Message(); ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream()); //此处代替数据库密码验证 if(u.getPasswd().equals("12345")){ //返回一个成功登录的信息包 m.setMesType("1"); oos.writeObject(m); //这里就单开一个线程,让该线程与该客户端保持通讯 SerConClientThread scct=new SerConClientThread(s); ManageClientThrea.addClientThrea(u.getUserId(), scct); //启动与该客户端通讯的线程 scct.start(); //并通知其它在线用户 scct.notifyOther(u.getUserId()); }else{ m.setMesType("2"); oos.writeObject(m); //关闭连接 s.close(); } } } catch (Exception e) { e.printStackTrace(); } }}*******************************************************************************
[SerConClientThread.java]
/** * 功能:是服务器与某个客户端的通讯线程 */package com.qq.server.model; import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.Socket;import java.util.HashMap;import java.util.Iterator;import com.qq.common.Message;import com.qq.common.MessageType; public class SerConClientThread extends Thread{ Socket s; public SerConClientThread(Socket s){ //把服务器与该客户端的连接赋给s this.s=s; } //让该线程去通知其它在线用户 public void notifyOther(String iam){ //得到所有在线的用户的线程 HashMap hm=ManageClientThrea.hm; Iterator it=hm.keySet().iterator(); while(it.hasNext()){ Message m=new Message(); m.setCon(iam); m.setMesType(MessageType.message_ret_onLineFriend); //取出在线用户的id String onLineUserId=it.next().toString(); try { ObjectOutputStream oos=new ObjectOutputStream(ManageClientThrea.getClientThrea(onLineUserId).s.getOutputStream()); m.setGetder(onLineUserId); oos.writeObject(m); } catch (IOException e) { e.printStackTrace(); } } } public void run(){ while(true){ //这里该线程就可以接收客户端发来的信息 try { ObjectInputStream ois=new ObjectInputStream(s.getInputStream()); Message m=(Message)ois.readObject(); System.out.println(m.getSender()+" 给 "+m.getGetder()+" 说:"+m.getCon()); //对从客户端取得的消息进行类型判断,然后做相应的处理 if(m.getMesType().equals(MessageType.message_comm_mes)){ //服务器完成转发功能 //取得接收人的通讯线程 SerConClientThread sc=ManageClientThrea.getClientThrea(m.getGetder()); ObjectOutputStream oos=new ObjectOutputStream(sc.s.getOutputStream()); oos.writeObject(m); }else if(m.getMesType().equals(MessageType.message_get_onLineFriend)){ //把在服务器的好友给该客户端返回 String res=ManageClientThrea.getAllOnLineUserid(); Message m2=new Message(); m2.setMesType(MessageType.message_ret_onLineFriend); m2.setCon(res); m2.setGetder(m.getSender()); ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream()); oos.writeObject(m2); } } catch (Exception e) { e.printStackTrace(); } } }}*******************************************************************************
[ManageClientThrea.java]
/** * 这是一个管理客户端线程的类 */package com.qq.server.model; import java.util.HashMap;import java.util.Iterator; public class ManageClientThrea { public static HashMap hm=new HashMap<String,SerConClientThread>(); //向hashmap中添加一个客户端通讯线程 public static void addClientThrea(String uid,SerConClientThread scct){ hm.put(uid,scct); } public static SerConClientThread getClientThrea(String uid){ return (SerConClientThread)hm.get(uid); } //返回当前在线的人的好友情况 public static String getAllOnLineUserid(){ //使用迭代器完成 Iterator it=hm.keySet().iterator(); String res=""; while(it.hasNext()){ res+=it.next().toString()+" "; } return res; }}*******************************************************************************
com.qq.common
[Message.java]
/** * 为Message规定规则 * mesType1-->表明登录成功 * mesType2-->表明登录失败 * mesType3-->表明普通消息包 */package com.qq.common; import java.io.Serializable; public class Message implements Serializable{ private String mesType; private String sender; private String getder; private String con; private String sendTime; public String getGetder() { return getder; } public void setGetder(String getder) { this.getder = getder; } public String getSender() { return sender; } public void setSender(String sender) { this.sender = sender; } public String getCon() { return con; } public void setCon(String con) { this.con = con; } public String getSendTime() { return sendTime; } public void setSendTime(String sendTime) { this.sendTime = sendTime; } public String getMesType() { return mesType; } public void setMesType(String mesType) { this.mesType = mesType; }}*******************************************************************************
[MessageType.java]
/** * 定义消息包的种类的接口 */package com.qq.common; public interface MessageType { String message_succeed="1";//登录成功包 String message_login_fail="2";//登录失败包 String message_comm_mes="3";//普通消息包 String message_get_onLineFriend="4";//要求在线的好友包 String message_ret_onLineFriend="5";//返回在线好友包}*******************************************************************************
[User.java]
/** * 这是用户信息类 */package com.qq.common; import java.io.Serializable; public class User implements Serializable{ private String userId; private String passwd; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; }}
浙公网安备 33010602011771号