基于TCP 的多线程 聊天程序

 

/*
 * 功能:聊天的客户端
 *soft05jun
 *08.3.12
*/

import  java.net. * ;
import  java.util. * ;
import  java.io. * ;

class  connet  implements  Runnable
{
    Socket localsocket;
    DataInputStream in
=null;
    DataOutputStream out
=null;
    Thread send,rec;
    Scanner read;          
//读入流对象
    connet(String address,int port)
    
{
        send
=new Thread(this);
        rec
=new Thread(this);
        read
=new Scanner(System.in);
        
try
        
{
            localsocket
=new Socket(address,port);
            in
=new DataInputStream(localsocket.getInputStream());
            out
=new DataOutputStream(localsocket.getOutputStream());
        }

        
catch(IOException e)
        
{
            System.out.print(
"套接字创建失败,原因:"+e);
            System.out.println(
"请检查服务器IP、端口是否正确");
        }

        System.out.println(
"连接成功,可以进行聊天了");
        send.start();
        rec.start();
    }

    
public void send()
    
{
        
while(true)
        
{
            
try
            
{
                out.writeUTF(read.nextLine());
            }

            
catch (IOException e)
            
{
                System.out.println(
"写入信息时失败");
            }

        }

    }

    
public void rec()
    
{
        
while(true)
        
{
            
try
            
{
                System.out.println(in.readUTF());
            }

            
catch(IOException e)
            
{
                System.out.println(
"读取服务器信息失败");
            }

        }

    }

    
public void run()
    
{
        
if(Thread.currentThread()==send)
        
{
            System.out.println(
"send线程启动,进入发送状态");
            
this.send();
        }

        
if(Thread.currentThread()==rec)
        
{
            System.out.println(
"rec线程启动,进入接收监听状态");
            
this.rec();
        }

    }

    
}


class  client
{
    
public static void main(String args[])
    
{

        String ip
=null;
        
int port=2526;  //默认是2526
        try
        
{
            ip
=new String(InetAddress.getLocalHost().getHostAddress());
        }

        
catch(Exception e)
        
{
            System.out.println(
"获取本地IP地址出错,请检查本地网络连接。");
        }

        Scanner reader
=new Scanner(System.in);
        System.out.println(
"请输入服务器IP:");
        ip
=reader.nextLine();
        System.out.println(
"服务器端口:");
        port
=reader.nextInt();
        System.out.println(
"正在连接服务器的IP地址是:"+ip+" 端口是:"+port);
        connet c
=new connet(ip,port);    

    }

}

 

 

import  java.net. * ;
import  java.util.Scanner;
import  java.io. * ;
import  java.util. * ;
/*
 * 此是服务器端
 * soft05jun
 * 08.3.14
 * 改进:其实current_thread,thread_num,mslist等变量可以声明为全家的静态变量比较好。这样就
 * 省掉了 传递的开销。
 
*/

class  message      // 消息类.
{
    
int id=0;
    String ms;
    message(
int id,String ms)
    
{
        
this.id=id;
        
this.ms=ms;
    }

}

class  serverconnet   // 服务器监听线程
{
    ServerSocket localsocket;
    LinkedList
<message> mslist;
    
static Vector current_thread;
    
static int threadnum;
    serverconnet(
int port)
    
{
        
try
        
{
            localsocket 
=new ServerSocket(port);
        }

        
catch(IOException e)
        
{
            System.out.println(
"服务器端套接字创建失败,请检查端口是否冲突。如冲突,请换用其它端口");
        }

        mslist
=new LinkedList<message>();   //消息链表(用队列比较好.)
        current_thread=new Vector();           //在线列表.(线程列表哦)
        threadnum=current_thread.size();                    //线程数目.(用 在线容器 里线程数量来赋值)
        
        
new control(mslist,current_thread).start();   //启动控制线程.(其实这个时候启
                                                
//动未必好,因为当没有客户连接过来时,它子线程也一直在运行.浪费CPU
    }

    
    
public void work()
    
{
        System.out.println(
"正在监听~");
        Socket s
=null;
        
while(true)
        
{
            
try
            
{
                s
=localsocket.accept();
                System.out.println(
"接收到一个客户连接请求,它的地址:"+s.getInetAddress());
            }

            
catch(IOException e)
            
{
                System.out.println(
"接受连接请求出现异常~");
            }

            
if(s!=null)
            
{
                xiancheng thread
=new xiancheng(s);
                System.out.println(
"当前线程编号:"+threadnum);
                thread.setid(threadnum);     
//线程ID设置.
                thread.setmsg(mslist);         //将此 消息队列 传参过去.
                
                current_thread.add(threadnum,thread);   
//加入在线列表.第一个参数为此对象的索引,类似数组下标。
                threadnum++;
                thread.start();
                
                
            }

        }

    }

    
public static void remove(int id)
    
{
        current_thread.remove(id);
        threadnum
--;
        
    }

    
}

class  control  extends  Thread    // 控制线程
{
    LinkedList
<message> mslist;
    Vector current_thread;
    
int threadnum; //在线线程数目。
    String ms=null;
    control(LinkedList
<message> mslist,Vector current_thread)
    
{
        
this.mslist=mslist;
        
this.current_thread=current_thread;
    }

    
    
public void run()   
    
{
        
while(true)   //这里写得并不高效.可以把链表操作次数再减少,以提高效率.
        {
            
if(mslist.isEmpty())
            
{
                
try
                
{
                    Thread.sleep(
1000);
                }

                
catch(InterruptedException e)
                
{
                    System.out.println(
"线程休眠失败.");
                }

                
continue;
                
//Thread.yield();  //测试发现,此函数并没有很好提高CPU性能,反而是占用率100%
            }

            
else
            
{
                threadnum
=current_thread.size();
                ms
=new String("线程ID为:"+mslist.getFirst().id+"的客户说:"+mslist.getFirst().ms);
                
                
for(int i=0;i<threadnum;i++)
                
{
                    xiancheng thread
=(xiancheng)current_thread.elementAt(i);
                    thread.send(ms);
                }

                mslist.removeFirst();
            }

        }

    }

}

class  xiancheng  extends  Thread   // 服务线程
{
    DataOutputStream out
=null;
    DataInputStream in
=null;
    String ms
=null;
    Socket socket;
    Scanner read;          
//读入流对象
    String shiyan;
    
    LinkedList
<message> msglist;
    
int id=0;
    
    xiancheng(Socket s)
    
{
        socket
=s;
        
try
        
{
            in
=new DataInputStream(socket.getInputStream());
            out
=new DataOutputStream(socket.getOutputStream());
        }

        
catch(IOException e)
        
{
            System.out.println(
"这里出现异常~");
        }

    }

    
public void run()
    
{
        
while(true)
        
{
            
try
            
{
                msglist.add(
new message(id,in.readUTF()));
            }

            
catch(IOException e)
            
{
                System.out.println(
"读写异常~,客户端可能已经退出。");
                serverconnet.remove(
this.id);         //调用static 方法,移除在线列表。
                break;
            }

        }

    }

    
public void send(String ms)
    
{
        
synchronized(out)                   //线程同步~~~~~!!!!!!!!!
        {
            
try
            
{
                out.writeUTF(ms);
            }

            
catch(IOException e)
            
{
                System.out.println(
"线程同步异常:"+e);
            }

        }

    }

    
public void setid(int threadnum)   //设置线程编号.
    {
        
this.id=threadnum;
    }

    
public void setmsg(LinkedList<message> mslist)   //设置消息链表.
    {
        
this.msglist=mslist;
    }

}




public   class  server 
{
    
public static void main(String args[])
    
{
        
int port=2526;
        System.out.println(
"请输入服务器监听端口号");
        Scanner reader
=new Scanner(System.in);
        port
=reader.nextInt();
        serverconnet ss
=new serverconnet(port);
        System.out.println(
"服务器正在监听"+port+"端口,等待客户连接");
        ss.work();
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值