一:什么是Socket
它實際上是網(wǎng)絡(luò)通信的一種接口,基于不同的協(xié)議,有各種不同的Socket,比如有基于TCP協(xié)議的Socket和基于UDP協(xié)議的Socket以及基于藍牙協(xié)議的Socket,Android中使用的是Java的Socket模型。
Socket在計算機行業(yè)通常稱為”套接字“,用于描述IP地址和端口,是一個通信鏈的句柄。這是一個比較抽象的概念。計算機是擁有端口的,每一個端口都可以有一個應(yīng)用程序來進行通訊的使用,比如:80端口是HTTP協(xié)議所使用的端口,21端口是FTP協(xié)議所使用的端口,端口是計算機和外界通訊的接口,這些接口都是邏輯的接口,端口號取值的范圍是零到256乘以256減1,1024以下的端口都是操作系統(tǒng)使用的保留端口,以上的端口我們可以自由的來使用,不要和其他應(yīng)用程序的端口沖突。
應(yīng)用程序可以通過“套接字”向網(wǎng)絡(luò)發(fā)送請求或者應(yīng)答網(wǎng)絡(luò)的請求,這時候就把Socket分成了兩部分,一部分是服務(wù)器端的Socket,這個Socket主要用來接收來自網(wǎng)絡(luò)的請求,它一直監(jiān)聽在某一個端口上。一部分是客戶端的Socket,這個Socket主要用來向網(wǎng)絡(luò)發(fā)送數(shù)據(jù)。
二:Socket通訊模型
-UDP協(xié)議和TCP協(xié)議
UDP協(xié)議和TCP協(xié)議是互聯(lián)網(wǎng)使用最廣的兩種協(xié)議都是基于IP的協(xié)議。第一個區(qū)別是UDP協(xié)議是一個不太靠譜的協(xié)議,UDP協(xié)議把數(shù)據(jù)都打成數(shù)據(jù)包,數(shù)據(jù)包上自帶通訊地址,也就是說我要把這個數(shù)據(jù)包發(fā)送到網(wǎng)絡(luò)上的哪一個地址,通過網(wǎng)絡(luò)把這個數(shù)據(jù)包發(fā)送出去,至于這個數(shù)據(jù)包是否發(fā)送到目的地,是否服務(wù)器端接收到了這個數(shù)據(jù)包,這個協(xié)議并不保證,就像中國的郵政,你是把信寄出去了,但是郵政系統(tǒng)不保證對方能收到你寄送的信。TCP發(fā)送數(shù)據(jù)的時候要求接收方接收到數(shù)據(jù)之后給一個回應(yīng),也就是你是否收到了,TCP可靠一些,當(dāng)我們發(fā)送一些比較重要的數(shù)據(jù)的時候一般都使用TCP協(xié)議。另外一個區(qū)別是UDP協(xié)議發(fā)送的一個數(shù)據(jù)包它的容量是有限的,而TCP協(xié)議則沒有這樣一個限制。并不是說UDP協(xié)議一定就不如TCP協(xié)議,在不同的領(lǐng)域有不同是使用,UDP協(xié)議好處是速度相對快些。TCP協(xié)議相對慢些。
-Socket通訊流程
應(yīng)用程序通過“套接字”也就是Socket可以選擇這兩種協(xié)議當(dāng)中的一種,你可以選擇用UDP發(fā)送數(shù)據(jù),也可以選擇用TCP發(fā)送數(shù)據(jù),數(shù)據(jù)發(fā)送出去通過“通信信道”也就是IP的基礎(chǔ)網(wǎng)絡(luò),來到服務(wù)器端(接收端),就可以接收到數(shù)據(jù)了。發(fā)送數(shù)據(jù)的時候用UDP協(xié)議,接收的時候也要用UDP協(xié)議,發(fā)送數(shù)據(jù)的時候用TCP協(xié)議,接收的時候也要用TCP協(xié)議,在發(fā)送的時候指定接收端的IP地址和端口號就可以了,究竟數(shù)據(jù)包或數(shù)據(jù)是如何發(fā)送的,框架已經(jīng)幫我們封裝好了,我們不去關(guān)心它了。
這篇博文介紹基于TCP協(xié)議來進行數(shù)據(jù)的發(fā)送,通常用于發(fā)送文件采用這種方式。
一:TCP協(xié)議通訊模型
1:工作流程
首先有兩部分客戶端和服務(wù)器端,客戶端需要Socket這個類的對象,而服務(wù)器端需要ServerSocket這個類的對象,由客戶端Socket發(fā)送一個請求,服務(wù)器端的ServerSocket在計算機的某一個端口號上進行監(jiān)聽,監(jiān)聽客戶端發(fā)送的請求之后,那么客戶端和服務(wù)器端的一個通訊通道就建立起來了,這時候呢既可以從客戶端向服務(wù)器端發(fā)送數(shù)據(jù),服務(wù)器端也可以給客戶端相應(yīng)的響應(yīng)。在客戶端發(fā)送數(shù)據(jù)的時候我們需要用到IO流里面的OutputStream,通過這個OutputStream把數(shù)據(jù)發(fā)送給服務(wù)器端,服務(wù)器端用InputStream來讀取客戶端當(dāng)中用OutputStream所寫入的數(shù)據(jù)。生活舉例:就像雙方男女朋友打電話一樣,男孩(客戶端)說話(數(shù)據(jù))通過聽筒發(fā)送到電話網(wǎng)絡(luò)中去,當(dāng)男孩說話的時候就相當(dāng)于咱們這里的通過OutputStream向互聯(lián)網(wǎng)中寫入數(shù)據(jù),而作為接聽的這個女孩(服務(wù)器端)那么男孩(客戶端)說的內(nèi)容就是女孩(服務(wù)器端)聽到的內(nèi)容,那么就是說服務(wù)器端可以通過InputStream把客戶端當(dāng)中通過OutputStream所寫入的數(shù)據(jù)給它讀取出來,反之亦然,如果服務(wù)器端想向客戶端發(fā)送數(shù)據(jù),那么就使用OutputStream寫出數(shù)據(jù),在客戶端通過InputStream把服務(wù)器端當(dāng)中通過OutputStream所寫入的數(shù)據(jù)給它讀取出來。就像打電話一樣,你說的就是我聽的,你聽的就是我說的。
二:通過基于TCP協(xié)議發(fā)送和讀取數(shù)據(jù)
1:布局文件main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="啟動監(jiān)聽線程"
android:id="@+id/btn1"/>
</LinearLayout>
2.1:服務(wù)器端Socket代碼文件MainActivity.java
package com.szy.socket;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MainActivity extends Activity
{
private Button btn1 = null;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(new Btn1Listener());
}
private class Btn1Listener implements OnClickListener{
@Override
public void onClick(View v){
new ServerThread().start();
}
}
private class ServerThread extends Thread
{
public void run()
{
ServerSocket serverSocket = null;
try{
serverSocket = new ServerSocket(4567);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
byte data[] = new byte[1024*4];
int i = 0;
while((i = inputStream.read(data)) !=1 )
Log.d("mytag",new String(data,0,i));
}catch (IOException e){
e.printStackTrace();
}
finally{
try{
serverSocket.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
}
}
2.2:客戶端Socket代碼文件TcpSocketClient.java
package com.szy.socketclient;
import android.app.Activity;
import java.net.Socket;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class TcpSocketClient extends Activity
{
public static void main(String[] args)
{
try{
Socket socket = new Socket("192.168.1.105",4567);
InputStream inputStream = new FileInputStream("C://www.txt");
OutputStream outputStream = socket.getOutputStream();
byte data[] = new byte[1024*4];
int i = 0;
while((i = inputStream.read(data)) !=1 ){
outputStream.write(data, 0, i);
}
outputStream.flush();
} catch (Exception e){
e.printStackTrace();
}
}
}
}