学java也有五个月了吧,学通信也三个月之后,而今我们四人小组用了大概一个月的时间做了这个通信项目,并为其正式命名为“云秘”!,没错,就是云秘,我们的初衷是做一个能集信息收集、管理、查询、共享资源并辅以聊天功能的项目,但是局限于时间不充裕,说来惭愧,现如今只是堪堪实现了其中的些许功能,但是值得欣慰的是我们组每天都在进步,每天都有码代码,即使学校的课程很紧,坚持总会有收获的,既已然收获,便是喜悦的,就不要去计较太多!
说那么多,现步入正题!我们的通信项目并未涉及数据库,所以很多对于数据,信息的处理用的都是对文件的读写操作! 作为一个通信项目,自然我们要有一个服务器!~
//在指定端口上创建一个服务器
public void setUpServer(int port){
try{
ss = new ServerSocket(port);
System.out.println("服务器创建成功");
//等待客户机连接,并设置成循环等待状态
while(true){
Socket client=ss.accept();
System.out.println("欢迎进入我的服务器");
//启动一个线程去处理该对象
ServerThread st=new ServerThread(client);
st.start();
ChatTools.add(st);
}
}catch(Exception ef){
ef.printStackTrace();
}
}
这个便是我的服务器,因为是服务器,后台的东西,所以并未做过多的界面处理!运用ServerSocket传入端口号建立服务器,循环等待客户机的连接,每当有客户端连接服务器,便启动一个线程来对该客户端与服务器之间的所有互动进行处理,再者用一个队列将该线程保存起来,后面会用到!
服务器的所有关键代码其实都在处理客户端的线程中体现了出来,一个好的服务器必须能有条不紊的处理大量的信息,所以服务器处理客户端的线程类一定要严谨!
//处理客户机进入的连接对象
public void processChat(Socket client){
try{
ins=client.getInputStream();
out=client.getOutputStream();
dis = new DataInputStream(ins);
dout=new DataOutputStream(out);
int t = dis.readInt();
while (true) {
// 如果读到的是1,调用读取消息
if (t == 1) {
readMsg();
}
// 读到的是2则调用保存注册信息的方法
if (t == 2) {
readlogon();
}
// 如果读到的是3,则调用核对登陆信息的方法
if (t == 3) {
checklogin();
}
// 如果读到的是4,则调用群发消息的方法
if (t == 4) {
allmsg();
}
//如果读到的是5,则调用单聊的方法
if (t == 5) {
sendone();
}
//如果读到的是6,则调用发送通知的方法
if (t == 6) {
sendtxt();
}
//如果读到的是7,则调用转发震动的方法
if (t == 7) {
readzhen();
}
//如果读到8,则调用关闭线程,通知下线的方法
if( t == 8){
closeThread();
}
//以下两个是发送表格填写的方法
if(t==HeadConfig.tableQuest){
readTableQuest();
}
if(t==HeadConfig.tableContent){
readTableContent();
}
t = dis.readInt();
}
} catch (Exception ef) {
ef.printStackTrace();
}
}
不同的协议分别调用不同的方法,一目了然!关于服务器的便说这么多,但是不得不说一个好的系统,服务器十分重要!!!
下面便说一说我们的客户端!
打开客户端,首先是一个登陆界面!
至于为什么用这张图片做背景,因为本人比较喜欢刘诗诗!
因为我们做这个项目刚开始设定的使用单位便是班级,所以我们验证信息时用的学号!在这个登陆界面上,我们在左上角更改了java图标,而我们的注册信息的图标也不是摆设!
我们现在注册了一个名为用户1的用户,当单机注册时,用户名以及账号密码会被发送到服务器去,也就是说在登陆界面打开的时候,其实客户端与服务器已经连接了....而服务器会把客户的信息利用IO流存在txt文件里,至于为什么用文件来村,实在是因为鄙人以及我们的小组目前对数据库知识还未掌握,不过目前正在学习中!!注册完了之后,注册界面会关闭并自动跳转回登陆界面!此时我们只要输入刚才注册的账号密码即可 !
当我们单击登陆界面时,客户机会把输入的账号密码发送到服务器去!!服务器会遍历自己存储客户姓名账号密码的的txt文件
// 定义一个核对登陆信息的方法
public void checklogin() {
try {
BufferedReader brd = new BufferedReader(new InputStreamReader(ins));
// input为发送过来的账号和密码
String input = brd.readLine();
try {
File file = new File(path);// 指定要读取的文件
if (!file.exists()) {// 如果文件不存在则创建
file.createNewFile();
} else {
// 获取该文件的缓冲输出流
BufferedReader bufferedreader = new BufferedReader(
new FileReader(file));
check(input, bufferedreader);//调用核对信息的方法
bufferedreader.close();// 关闭输出流
}
} catch (Exception ef) {
ef.printStackTrace();
}
} catch (Exception ef) {
ef.printStackTrace();
}
}
// 定义一个核对账号密码的方
public void check(String str, BufferedReader bufferedreader) {
String line1="";
try {
String line = bufferedreader.readLine();
if (line != null) {
if (line.equals(str)) { //如果文件中读到信息与客户端传入的登陆信息匹配,则返回一个right,通过登陆严重
line1 = bufferedreader.readLine();
name=line1;
setName(line1);
sendcheck("right/"+line1);
thsendname.start();
// runjudge.start(); //上线提示
ServerTools.add(line1);// 将登陆的用户名添加到队列里
} else if (!line.equals(str)) {
check(str, bufferedreader);
}
} else {
sendcheck("no");
}
} catch (Exception ef) {
}
}
通过验证正是进入属于客户自己的界面了!!!附图如下:
可以看见界面左上角的昵称便是刚才我们注册时的“用户1”;昵称下面便是四个按钮对应四个我们基本实现的功能!
一、 第一个群聊功能---------------------------------------
两个继承了JTextPane的显示框,因为一般的现实框并不能实现对于jif表情图片的现实功能!关于表情的发送以及接受我们也是弄了一段时间,这要感谢组员钟楚斌的贡献!因为表情发送其图片的字符串过来,然后又根据其字符串在本地找到相对于的图片再将其显示在JTextPane上,一个表情的可能是插在一段文字中发送过来的,所以难点就是你要去识别它是表情还是消息!先附上读取带有表情文本的读取方法。
//定义一个读取带有表情的消息的方法
public void readface(String input,JTextPane1 jt_recive){
int in=0;
String temp1="";
String temp2= "";
String h1 = "expression//";
String h2 = ".gif";
//如果没有表情
if((in=input.lastIndexOf("\\"))==-1){
jt_recive.insert_text(input);
}
else{//如果有表情
int mark=-4;//标记上次表情出现的位置
for(int i=0;i<input.length();i++){
if(input.charAt(i)=='\\'){
temp1 = input.substring(mark+4, i);
jt_recive.insert_text(temp1);
String loc = input.substring(i+1,i+4);
int loc_exp = Integer.parseInt(loc);
jt_recive.insert_icon(h1+loc_exp+h2);
mark=i;
}
else{
temp2 = input.substring(mark+5, input.length());
}
}
jt_recive.insert_text(temp2);
}
jt_recive.insertln("");
}
如此便能成功的读取表情了!看似简单,其中确实颇为费力!
二、进入通知的编辑,浏览界面,默认进入的编辑界面
双击进入编辑界面
读到的是第一条通知,通知是先保存在文件中的,当用户需要浏览时,才从文件中提取通知内容!
再次双击进入的是我们四个功能的总界面,当然你也可以关掉,从刚才我们主界面的四个按钮中分别进入这些界面!
三、就是我们对于数据收集以及能提供客户查询相应信息的版块!!
四、就是我们想实现链接我们学校主页的方法,无奈级数不纯熟,只得弄了个链接wap百度的暂时顶替下
关于网页链接的代码,附上如下:
package 云秘;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Font;
import java.net.URL;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
public class News extends JFrame implements Runnable{
private JEditorPane newsPane;
private String newsURL = "http://m.baidu.com";
public News() {
try {
newsPane = new JEditorPane(new URL(newsURL));
newsPane.setBackground(Color.orange);
} catch (Exception e) {
e.printStackTrace();
}
newsPane.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
Desktop browser = Desktop.getDesktop();
try {
browser.browse(e.getURL().toURI());
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
});
newsPane.setEditable(false);
add(newsPane);
setSize(400,400);
setLocation(300,150);
setVisible(true);
}
public void stop(){
this.dispose();
}
public void run(){
new News();
}
}
当然我们实现的聊天功能不止有群聊,还有单聊!!
当我单击对应的用户时,便弹出与其的对话框,但我们把消息发过去的时候,是把该对象的名字,以及发送的字符串一起发送给服务器的!
jbsend.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
String msg = jt_send.getText();
threadTwo.sendbyte(5);
msg=name+"!说:"+msg;
threadTwo.sendmsg(msg);
String[] mesg=msg.split("!");
threadTwo.readface("我"+mesg[1],jt_recive);
jt_send.setText("");
}
});
服务器调用转发单聊的方法,首先先根据你发过来对象的名字,找到该对象相对应的线程对象,调用线程的发送方法把你要说的话用他的线程发送给他
//定义一个单独处理指定对象发送消息的方法
public void sendone(){
String input="";
try {
BufferedReader brd = new BufferedReader(new InputStreamReader(ins));
String mesg = brd.readLine();
String[] msg=mesg.split("\\!");//截取字符串,按标识符划分成数组
String name=msg[0];//字符串第一部分便是发送过来对象的名字
for(int i=0;i<ChatTools.getsize();i++){//遍历存储线程的队列找到相应的线程调用发送方法
ServerThread st=ChatTools.get(i);
if(st.getName().equals(name)){
input=this.getName()+"!"+msg[1];
st.sendbyte(5);
st.sendMsg(input);
}
}
}catch (Exception ef) {
ef.printStackTrace();
}
}
关于读取的方法便是和群聊的方法大同小异了!!
如此一来通信项目也搞了一段落,虽然最终的成果并不如我们预期的一般,但是就目前对通信这一块的掌握情况来说,剩下的那些未解决的东西确实只是时间问题而已!譬如说我们的客户上线的提醒问题,譬如说我们的好友列表的问题,所以说搞项目就该有一个持之以恒的心,成功向来不易,轻易得来的成功便不算成功!!!!!!!!!!!
(再次感谢我们小组的其他三个人——杨星,钟楚斌,朱凌峰)