雜談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());
}
}
}
}