java服务器端线程体会
一个完整的项目包括服务器和客服端
服务器端初步编写:
(1)
服务器端应用窗口的编写 (服务器类Server):
包括窗口和组件的一些设置, 添加一些客服端的元素,如客服端在线用户表(Vector), 服务端接口ServerSocket, 服务端线程ServerThread
其次就是组件的事件监听以及相应的事件方法
(2)
服务器线程的编写 (服务器线程类 ServerThread):
服务器线程起分配服务器代理线程作用,接受客服端的连接同时为其分配一个专用的服务器代理线程.
编写相对简单,给出服务器(Server) 通过其服务端接口(ServerSocket)监听客服端的连接(Socket),同时为其分配代理线程(ServerAgentThread)
public class ServerThread extends Thread { Server father; //声明Server的引用 ServerSocket ss;//声明ServerSocket的引用 boolean flag=true; public ServerThread(Server father) {//构造器 this.father=father; ss=father.ss; } public void run() { while(flag) { try { Socket sc=ss.accept();//等待客户端连接 ServerAgentThread sat=new ServerAgentThread(father,sc); sat.start();//创建并启动服务器代理线程 } catch(Exception e) { e.printStackTrace(); } } } }
(3)
服务器代理线程(ServerAgentThread) :代理线程对应相应的客服端 起到接受发送信息作用 一个服务器代理线程与一个客服端唯一对应
服务器代理线程类是服务器主要类,
其中包括一些基本的代理线程内容 如服务器(Server) 客服端连接(Socket) 数据输入输出(DateInputStream DateOutputStream)
还有与客服端的数据的一些交流方法, 线程run方法起判断客服端信息作用
public class ServerAgentThread extends Thread { Server father;//声明Server(服务器Server)的引用 Socket sc;//声明Socke(客服端接口Socket)t的引用 DataInputStream din;//声明数据输入流与输出流 DataOutputStream dout; boolean flag=true;//控制线程的生命周期 public ServerAgentThread(Server father,Socket sc) { //构造方法一般初始化 服务器 客服端接口 还有应用端接口数据输入输出 this.father=father; this.sc=sc; try { din=new DataInputStream(sc.getInputStream());//创建数据输入流 dout=new DataOutputStream(sc.getOutputStream());//创建数据输出流 } catch(Exception e) { e.printStackTrace(); } } public void run() { while(flag) { try { String msg=din.readUTF().trim(); //接收客户端传来的信息判断并作出相应的回应 //其中单个回应一般包含对服务器端的操作数据回应 以及对客服端的操作数据回应 if(msg.startsWith("c"))//收到新用户的信息 { this.nick_name(msg); } else if(msg.startsWith("<#CLIENT_LEAVE#>")){ this.client_leave(msg); } else if(msg.startsWith("<#TIAO_ZHAN#>")){ this.tiao_zhan(msg); } else if(msg.startsWith("<#TONG_YI#>")){ this.tong_yi(msg); } else if(msg.startsWith("<#BUTONG_YI#>")){ this.butong_yi(msg); } else if(msg.startsWith("<#BUSY#>")){ this.busy(msg); } else if(msg.startsWith("<#MOVE#>")){ this.move(msg); } else if(msg.startsWith("<#RENSHU#>")){ this.renshu(msg); } } catch(Exception e) { e.printStackTrace(); } } } //单个操作方法的书写 //此处省略几个 //新用户 public void nick_name(String msg) { try { String name=msg.substring(13);//获得用户的昵称 this.setName(name);//用该昵称给该线程取名 Vector v=father.onlineList;//获得在线用户列表 boolean isChongMing=false;//重名flag int size=v.size();//获得用户列表的大小 for(int i=0;i<size;i++) { //遍历列表,查看是否已经有该用户名 ServerAgentThread tempSat=(ServerAgentThread)v.get(i); if(tempSat.getName().equals(name)) { isChongMing=true;//有重名,将标志位设为true break; } } if(isChongMing==true)//如果重名 { dout.writeUTF("<#NAME_CHONGMING#>");//将重名信息发送给客户端 din.close();//关闭数据输入流 dout.close();//关闭数据输出流 //重点部分 重名需要终止分配的该服务器代理线程以免产生安全问题 sc.close();//关闭Socket flag=false;//终止该服务器代理线程 } else//如果不重名 { v.add(this);//将该线程添加到在线列表 father.refreshList();//刷新服务器在线信息列表 String nickListMsg=""; size=v.size();//获得在线列表大小 //(实时更新) for(int i=0;i<size;i++) { ServerAgentThread tempSat=(ServerAgentThread)v.get(i); nickListMsg=nickListMsg+"|"+tempSat.getName(); } nickListMsg="<#NICK_LIST#>"+nickListMsg; //将在线用户组成字符串 <#NICK_LIST#>|1|2|3|4|5|6|7 Vector tempv=father.onlineList; size=tempv.size(); for(int i=0;i<size;i++) {//遍历在线列表 ServerAgentThread satTemp=(ServerAgentThread)tempv.get(i); satTemp.dout.writeUTF(nickListMsg);//将最新的列表信息发送到各个客户端 if(satTemp!=this) {//给其他客户端发送新用户上线的信息 satTemp.dout.writeUTF("<#MSG#>"+this.getName()+"上线了..."); } } } } catch(IOException e) { e.printStackTrace(); } } } //用户下线 public void client_leave(String msg){ try{ Vector tempv=father.onlineList;//获得在线列表 tempv.remove(this);//移除该用户代理线程 int size=tempv.size(); String nl="<#NICK_LIST#>"; for(int i=0;i<size;i++){//遍历在线列表 ServerAgentThread satTemp=(ServerAgentThread)tempv.get(i); //向各个客户端发送用户离线信息 satTemp.dout.writeUTF("<#MSG#>"+this.getName()+"离线了..."); //组织信息的在线用户列表 nl=nl+"|"+satTemp.getName(); } for(int i=0;i<size;i++){//将最新的列表信息发送到各个客户端 ServerAgentThread satTemp=(ServerAgentThread)tempv.get(i); satTemp.dout.writeUTF(nl); } (重点部分 线程下线需要关闭其相关代理) this.flag=false;//终止该服务器代理线程 father.refreshList();//更新服务器在线用户列表 } catch(IOException e){e.printStackTrace();} }