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();}
        }