多线程和网络编程实践——LittleTom

这两天写了一个小应用,实现基本的聊天功能。该应用既是客户端也是服务器,不要求某一方先发起连接请求。但同一时间仅能两个ip互相传输数据。用上了最近学的多线程和网络编程相关知识。先贴上初稿,还有问题,以后有空再琢磨琢磨。

两个类:LittleTom.class, TalkThread.class

1. LittleTom.java

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

public class LittleTom {
    private Wait waitThread = null;
    private Connect connectThread = null;
    private ServerSocket waitSocket;
    private Socket socket;
    private BufferedReader br = null;
    private int waitPort = 10001;
    private int connectPort = 10002;
    private boolean isConnecting = false;
    
    public LittleTom() {
        br = new BufferedReader(new InputStreamReader(System.in));
        
        waitThread = new Wait();
        connectThread = new Connect();
        
        waitThread.start();
        connectThread.start();
    }
    
   class Wait extends Thread {
       public void run(){
           waitConnect();
       }
       
       synchronized private void waitConnect() {
           try {
               waitSocket = new ServerSocket(waitPort);
               while(true) {                          
                   if(!isConnecting) {
                       Socket memberSocket = waitSocket.accept();
                       if(!isConnecting) {
                           isConnecting = true;
                           System.out.println(memberSocket.getInetAddress().getHostName() + " want to talk with you.");
                           new TalkThread(LittleTom.this, memberSocket);
                       } else {
                           System.out.println("Wait::You can only speak with one preson at the same time.");
                           continue;
                       }
                   } else {
                       wait();
                   }
               }
           } catch(Exception e) {
               e.printStackTrace();
           } finally {
               try {
                   if(waitSocket != null){
                       waitSocket.close();
                   }
                  
                   if(socket != null) {
                       socket.close();
                   }

                   br.close();
               } catch(Exception e) {
                   e.printStackTrace();
               }
           }
       }
   }
   
   class Connect extends Thread {
       public void run(){
           tryToConnect();
       }
       synchronized private void tryToConnect() {
           try{
               while(true) {
                   if(!isConnecting) {
                       System.out.println("Please input the IP that you want to talk with: ");
                       br = new BufferedReader(new InputStreamReader(System.in));
                       String input = br.readLine();
//                       String IP = "109.123.102.117";
                       if(!isConnecting) {
                           isConnecting = true;
                           System.out.println("Try to connecting...");
                           socket = new Socket(input, connectPort);
                           new TalkThread(LittleTom.this, socket); 
                           
                       } else {
                           System.out.println("Connect::You can only speak with one preson at the same time.");
                           continue;
                       }
                   } else {
                       wait();
                   }
               }
           } catch(Exception e) {
               System.out.println("connect fail.");
               e.printStackTrace();
           } finally {
               try {
                   if(waitSocket != null){
                       waitSocket.close();
                   }
                  
                   if(socket != null) {
                       socket.close();
                   }

                   br.close();
               } catch(Exception e) {
                   e.printStackTrace();
               }
           }
       }
   }
   

   public void resetConnection() {
        isConnecting = false;
        synchronized(waitThread) {
            waitThread.notify();
        }
        synchronized(connectThread) {
            connectThread.notify();
        }
    }
   
    public BufferedReader getSystemBuffer() {
        return br;
    }

    public static void main(String[] args) {
            LittleTom lt = new LittleTom();
    }
    
}

2. TalkThread.java

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


public class TalkThread {
    private LittleTom littleTom;
    private Socket memberSocket;
    private String peer;
    private InputStream is;
    private OutputStream os;
    
    private Thread receiveThrd = null;
    private Thread sendThrd = null;
   
    
    public TalkThread(LittleTom lt, Socket socket){
        try {
            this.littleTom = lt;
            this.memberSocket = socket;
            peer = memberSocket.getInetAddress().getHostName();
            is = memberSocket.getInputStream();
            os = memberSocket.getOutputStream(); 
            receiveThrd = new Thread() {
                public void run(){
                    receive();
                    sendThrd.stop();
                    close();
                    littleTom.resetConnection();
                }
            };

            sendThrd = new Thread() {
                public void run(){
                    send();
                    receiveThrd.stop();
                    close();
                    littleTom.resetConnection();
                }
            };
            
            receiveThrd.start();
            sendThrd.start();
        } catch(Exception e) {
            e.printStackTrace();
        } 
    }

    private void receive() {
        byte[] b = new byte[1024];
        String receiveMsg = null;
        try {
            do {
                int n = is.read(b);
                if(n<=0) {
                    continue;
                }
                receiveMsg = new String(b, 0, n); 
                System.out.println(peer + " say >>>> " + receiveMsg);
            } while(receiveMsg == null || !receiveMsg.equalsIgnoreCase("exit"));
        } catch(Exception e) {
            if(memberSocket.isClosed()){
                System.out.println("receive::socket is closed.");
            } else {
                e.printStackTrace();
            }
        }
    }
    
    private void send() {
//        byte[] b = new byte[1024];
        String input = null;
        try {
            do {
                input = littleTom.getSystemBuffer().readLine();
                if(input == null) {
                    continue;
                }
                System.out.println("I say >>>> " + input);
                os.write(input.getBytes());
            } while((input == null) || (!input.equalsIgnoreCase("exit")));
        } catch(Exception e) {
        	if(memberSocket.isClosed()){
                System.out.println("send::socket is closed.");
            } else {
                e.printStackTrace();
            }
        } 
    }
    
    public void close() {
        try {
            is.close();
            os.close();
            memberSocket.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}


    程序运行起来还有问题:

        1. 被动接受连接的一方,第一次用户输入的数据不能发送出去。原因是数据被tryToConnect读到,并被认为是用户输入的IP地址,所以尝试去连接。连接失败,打印"Connect::You can only speak with one preson at the same time.", 再次进入循环的时候,由于isConnecting==true,直接进入等待。然后后面用户的输入就能发送出去了。但是怎么修复这个bug啊?

        2. 连接只能进行一次。一方exit,然后再尝试去连就连不上了。但是程序并没有退出。求高手解答。

 

 


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值