杂谈socket编程

作者:xcbeyond
疯狂源自梦想,技术成就辉煌!微信公众号:《程序猿技术大咖》号主,专注后端开发多年,拥有丰富的研发经验,乐于技术输出、分享,现阶段从事微服务架构项目的研发工作,涉及架构设计、技术选型、业务研发等工作。对于Java、微服务、数据库、Docker有深入了解,并有大量的调优经验。












最近在写一些与网络编程相关的小工具,不得不再把网络编程的知识再回顾回顾了。一提起网络编程,势必局想到了一位核心人物Socket,是她撑起了网络编程的半边天,使得网络编程得以继续。

         什么是Socket?

        通常也称作"套接字",应用程序通过Socket向网络发出请求或者应答网络请求。它是在应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,用来组织传输的数据。下面就用一张图来说明下“三次握手”:

         

         网络间的通信,是建立在授受双方的,即:服务器与客户端。服务器端时刻处于启动状态,不停地监听着客户端发来的请求信息,并给予应答,当客户端向服务器发来一条数据请求时,服务器接受到了这条请求后,验证成功后,给出回复,建立链接通信,即一次握手。类似数据传输交换、断开链接又是两次握手。下面就以一段代码来做一分析说明吧。(Java版)

服务端:

<span style="font-size:14px;">import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * FTP服务器端
 * @author xcbeyond
 * 2014-6-7 22:12:21
 */
 
public class FtpServer {
    public static void main(String[] args) throws Exception{
        FtpServer server = new FtpServer();
        server.listen(8800);
        
    }
        //用来时刻监听来自客户端请求的监听者
    public void listen(int port) throws Exception{
        ServerSocket ss = new ServerSocket(port);
        while(true) {
            System.out.println("等待客户端连接...");
            Socket socket = ss.accept();
            System.out.println("客户连接进来了。");
            new ClientAgent(socket).start();
        }
    }
    
    class ClientAgent extends Thread{
        Socket socket;
        InputStream in;
        OutputStream out;
        public ClientAgent(Socket socket) throws Exception{
            this.socket = socket;
            in = socket.getInputStream();
            out = socket.getOutputStream();
        }
        @Override
        public void run() {
            BufferedReader in = new BufferedReader(
                                new InputStreamReader(this.in));
            PrintWriter out = new PrintWriter(this.out,true);//true自动清除缓存   相当于fulsh()
            try{
                out.println("text,1");
                out.println("你好欢迎使用FTP Demo!");
                while(true) {
                    String cmd = in.readLine();
                    if("?".equals(cmd)) {
                        out.println("text,1");
                        out.println("支持命令:ls,get,?,bye");
                    }
                    else if("ls".equals(cmd)) {
                        listDir(out);
                    }
                    else if(cmd.matches("^get\\s+.+")) {
                        sendFile(cmd,out,this.out);
                    }
                    else{
                        out.println("text,1");
                        out.println("不知可否!");
                    }
                }
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
        private void sendFile(String cmd, PrintWriter out,OutputStream os) throws IOException{
            String name = cmd.split("\\s+")[1];
            File file = new File(name);
            if(!file.exists()){
                out.println("text,1");
                out.println("没有找到文件! "+name);
                return;
            }
            out.println("file,"+file.length()+","+name);
            InputStream in = new BufferedInputStream(
                                    new FileInputStream(file));
            int b;
            while((b = in.read())!=-1){
                os.write(b);
            }
            os.flush();
            in.close();
        }
        /**
         * 列出文件目录
         * @param out
         */
        private void listDir(PrintWriter out) {
            File dir = new File(".");
            File[] files = dir.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    return pathname.isFile();
                }
            });
            out.println("text,"+files.length+1);
            out.println("在目录:"+dir+"中,有文件:"+files.length);
            for (File file : files) {
                out.println(file.getName());
            }
        }
    }
}
</span>

客户端:

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
/**
 * 
 * @author xcbeyond
 * 2014-6-7 23:16:53
 */
public class FtpClient {
    Socket socket;
    OutputStream out;
    InputStream in;
    public static void main(String[] args) throws Exception{
        FtpClient client = new FtpClient();
        client.open("localhost",8800);
    }
    public void open(String host,int port) throws Exception{
        socket = new Socket(host,port);   //对指定IP,端口的服务程序发出请求,建立通信
        in = socket.getInputStream();
        out =socket.getOutputStream();
        new RequestSender(out).start();
        new ResponseReceiver(in).start();
    }
    
    class RequestSender extends Thread{
        OutputStream out;
        public RequestSender(OutputStream out) {
            this.out = out;
        }
        @Override
        public void run() {
            PrintWriter out = new PrintWriter(this.out,true);
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            String str;
            try{
                while((str = in.readLine())!=null) {
                    out.println(str);
                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    class ResponseReceiver extends Thread {
        InputStream in;
        public ResponseReceiver(InputStream in) {
            this.in = in;
        }
        public void run() {
            BufferedReader in = new BufferedReader(new InputStreamReader(this.in));
            try{
                String str;
                while((str = in.readLine())!=null) {
                    if(str.startsWith("text")) {
                        String num = str.substring(str.indexOf(",")+1);
                        printText(in,Integer.parseInt(num));
                    }
                    else if(str.startsWith("file")){//file,4567,filename
                        saveFile(this.in,str);
                    }
                }
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * 保存文件
          * @param in
         * @param size
         */
        private void saveFile(InputStream in, String head) throws IOException{
            String[] data = head.split(",");
            int length = Integer.parseInt(data[1]);
            String name  = data[2];
            OutputStream out = new BufferedOutputStream(new FileOutputStream("ftp-"+name));
             for (int i = 0; i < length; i++) {
                int b = in.read();
                out.write(b);
            }
            out.close();
            System.out.println("下载了文件:"+name);
        }
         /**
         * 打印出文本内容
         * @param in
         * @param num
         * @throws Exception
         */
        private void printText(BufferedReader in, int num) throws Exception{
            for (int i = 0; i < num; i++) {
                System.out.println(in.readLine());
            }
        }
        
    }
}