雜談socket編程
作者:xcbeyond
瘋狂源自夢(mèng)想,技術(shù)成就輝煌!微信公眾號(hào):《程序猿技術(shù)大咖》號(hào)主,專注后端開發(fā)多年,擁有豐富的研發(fā)經(jīng)驗(yàn),樂于技術(shù)輸出、分享,現(xiàn)階段從事微服務(wù)架構(gòu)項(xiàng)目的研發(fā)工作,涉及架構(gòu)設(shè)計(jì)、技術(shù)選型、業(yè)務(wù)研發(fā)等工作。對(duì)于Java、微服務(wù)、數(shù)據(jù)庫、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗(yàn)。
最近在寫一些與網(wǎng)絡(luò)編程相關(guān)的小工具,不得不再把網(wǎng)絡(luò)編程的知識(shí)再回顧回顧了。一提起網(wǎng)絡(luò)編程,勢(shì)必局想到了一位核心人物Socket,是她撐起了網(wǎng)絡(luò)編程的半邊天,使得網(wǎng)絡(luò)編程得以繼續(xù)。
什么是Socket?
通常也稱作"套接字",應(yīng)用程序通過Socket向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求。它是在應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層,它是一組接口,用來組織傳輸?shù)臄?shù)據(jù)。下面就用一張圖來說明下“三次握手”:
網(wǎng)絡(luò)間的通信,是建立在授受雙方的,即:服務(wù)器與客戶端。服務(wù)器端時(shí)刻處于啟動(dòng)狀態(tài),不停地監(jiān)聽著客戶端發(fā)來的請(qǐng)求信息,并給予應(yīng)答,當(dāng)客戶端向服務(wù)器發(fā)來一條數(shù)據(jù)請(qǐng)求時(shí),服務(wù)器接受到了這條請(qǐng)求后,驗(yàn)證成功后,給出回復(fù),建立鏈接通信,即一次握手。類似數(shù)據(jù)傳輸交換、斷開鏈接又是兩次握手。下面就以一段代碼來做一分析說明吧。(Java版)
服務(wù)端:
<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服務(wù)器端
* @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);
}
//用來時(shí)刻監(jiān)聽來自客戶端請(qǐng)求的監(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("客戶連接進(jìn)來了。");
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自動(dòng)清除緩存 相當(dāng)于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); //對(duì)指定IP,端口的服務(wù)程序發(fā)出請(qǐng)求,建立通信
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());
}
}
}
}