雜談socket編程

作者:xcbeyond
瘋狂源自夢想,技術成就輝煌!微信公眾號:《程序猿技術大咖》號主,專注后端開發(fā)多年,擁有豐富的研發(fā)經(jīng)驗,樂于技術輸出、分享,現(xiàn)階段從事微服務架構項目的研發(fā)工作,涉及架構設計、技術選型、業(yè)務研發(fā)等工作。對于Java、微服務、數(shù)據(jù)庫、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗。

最近在寫一些與網(wǎng)絡編程相關的小工具,不得不再把網(wǎng)絡編程的知識再回顧回顧了。一提起網(wǎng)絡編程,勢必局想到了一位核心人物Socket,是她撐起了網(wǎng)絡編程的半邊天,使得網(wǎng)絡編程得以繼續(xù)。

         什么是Socket?

        通常也稱作"套接字",應用程序通過Socket向網(wǎng)絡發(fā)出請求或者應答網(wǎng)絡請求。它是在應用層與TCP/IP協(xié)議族通信的中間軟件抽象層,它是一組接口,用來組織傳輸?shù)臄?shù)據(jù)。下面就用一張圖來說明下“三次握手”:

         

         網(wǎng)絡間的通信,是建立在授受雙方的,即:服務器與客戶端。服務器端時刻處于啟動狀態(tài),不停地監(jiān)聽著客戶端發(fā)來的請求信息,并給予應答,當客戶端向服務器發(fā)來一條數(shù)據(jù)請求時,服務器接受到了這條請求后,驗證成功后,給出回復,建立鏈接通信,即一次握手。類似數(shù)據(jù)傳輸交換、斷開鏈接又是兩次握手。下面就以一段代碼來做一分析說明吧。(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);
        
    }
        //用來時刻監(jiān)聽來自客戶端請求的監(jiān)聽者
    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,端口的服務程序發(fā)出請求,建立通信
        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);
        }
         /**
         * 打印出文本內(nèi)容
         * @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());
            }
        }
        
    }
}