io-nio-socket步步为营(二)传统IO

 

二、传统Socket____________________________________________________________

需要实践TCP三次握手,四次分手,实践,不是只看理论!!!!!!!!!!!!!!!

1、socket与socketStream的关闭顺序,ServerScoket优雅关闭。

socket.close()注释这么说:Closing this socket will also close the socket's InputStream and OutputStream.但是,debug观察到的结果不是。

反而是关闭留后,会关闭socket,

 

 

2、最简单的socket,server只同时支持一个client的读写,尽管第二个client可以连接上可以write(server端阻塞在accept上),但是client会阻塞在getInputstream().read(),且不能优雅关闭,

 

server

 

/**
 * @author timeriver.wang
 * @date 2012-12-08 9:28:40 PM
 */
public class Server {
	public static void main(String[] args){
		ServerSocket ss;
		try {
			ss = new ServerSocket(8899);
			while (true) {
				Socket socket = ss.accept();
				InputStream is = socket.getInputStream();
				OutputStream os = socket.getOutputStream();
				BufferedReader netInput = new BufferedReader( new InputStreamReader( is ) );
				String receive = netInput.readLine();
				while(receive != null){
					System.out.println(receive);
					os.write(("server echo: " + receive+"\r\n").getBytes("UTF-8"));
					os.flush();
					if("bye".equals(receive)){
						break;
					}
					receive = netInput.readLine();
				}
				//用于测试关闭顺序,配合client的,比如去掉这句。
				os.close();
				socket.close();
				System.out.println(socket);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

client

升级:增加一个buffer队列,从键盘读数据是一个线程,如果buffer不满就写,否则阻塞,向socket发送数据是一个线程,如果buffer不空就读,否则阻塞。从socket读数据再设一个线程,直接输出。

 

/** 
 * @author timeriver.wang 
 * @date 2012-12-08 9:28:40 PM 
 */  
public class Client {  
    public static void main( String[] args ){  
        try {  
            Socket so = new Socket( "127.0.0.1", 8899 );  
            System.out.println(so);
            OutputStream os = so.getOutputStream();  
            InputStream is = so.getInputStream();  
            BufferedReader netInput = new BufferedReader( new InputStreamReader( is,"UTF-8" ) ); 
            BufferedReader keyInput = new BufferedReader( new InputStreamReader( System.in,"UTF-8" ) );  
                String keyLine = null;
                while((keyLine = keyInput.readLine())!=null){
                	System.out.println( "client say: " + keyLine );  
                	os.write( (keyLine+"\r\n").getBytes("UTF-8") );  
                	// write把数据发送给TCP层(操作系统网卡)缓存,一个TCP包20-40字节,为wirte每个byte单独发一个TCP包太奢侈,但可以flush  
                	os.flush();  
                	System.out.println(netInput.readLine());
                	if ( keyLine.equals( "bye" ) ) {  
                		break;  
                	}  
                }
                os.close();
            // 需要研究,主动关闭被动关闭FIN,RST,  //用于测试关闭顺序,配合服务器的,比如去掉这句。
//            so.close();  
            System.out.println( os );  
        }  
        catch ( Exception e ) {  
            e.printStackTrace();  
        }  
    }  
}  

 

 

3、多线程的serversocket, 可以支持多个client同时通信

 

/**
 * @author timeriver.wang
 * @date 2013-01-03 12:29:50 PM
 */

public class EchoServer {
    public static void main( String args[] )throws IOException {
        //更好的是这种方式new EchoServer().service();serverSocket,port通过构造函数初始化
        ServerSocket serverSocket = new ServerSocket( 8899 );
        while ( true ) {
            Socket socket = serverSocket.accept(); 
            Thread workThread = new Thread( new Handler( socket ) ); 
            workThread.start(); 
        }
    }
}

class Handler implements Runnable {
    //多线程只能通过构造传参,因为它的run方法是无参的,且只能通过run/start方法来启动一个新线程
    private Socket socket;
    public Handler( Socket socket ) {
        this.socket = socket;
    }
    public void run() {
        try {
            /**
             * 显示多个不同的socket连接,下面是console输出,2+main=3个线程,server端只需要一个port##
             * New connection accepted: Socket[addr=/127.0.0.1,port=57098,localport=8899]
             * client1-1
             * New connection accepted: Socket[addr=/127.0.0.1,port=57102,localport=8899]
             * client2-1
             * client1-2
             */
            System.out.println( "New connection accepted: " + socket);
            BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
            PrintWriter pw = new PrintWriter( socket.getOutputStream(), true );
            String msg = null;
            while ( ( msg = br.readLine() ) != null ) {
                System.out.println( msg );
                pw.println( "echo:" + msg );
                if ( msg.equals( "bye" ) )
                    break;
            }
        }catch ( IOException e ) {
            e.printStackTrace();
        }
        finally {
            try {
                if ( socket != null )
                    socket.close();
            }
            catch ( IOException e ) {
                e.printStackTrace();
            }
        }
    }
}

 

4,固定数量的连接,使用Executors
	public EchoServer() throws IOException {
		serverSocket = new ServerSocket(port);
		executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
				.availableProcessors() * POOL_SIZE);
	}
	public void service() {
		while (true) {
			Socket socket = null;
			try {
				socket = serverSocket.accept();
				//不同之处
				executorService.execute(new Handler(socket));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
 
5、主动关闭socket
while (!isShutdown) {
private boolean isShutdown=false;
改变isShutdown,public方法,或者通过socket thread。
 
半关闭
shutdownInput():关闭输入流。 
shutdownOutput(): 关闭输出流。
不会释放Socket占用的资 源,比如占用的本地端口等
比如QQ传送大文件一半时,取消发送,暂停,断点续传?
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值