Android學習筆記(30) --- 網絡通信之Socket簡單使用

關於Socket,百度百科是這麼說的:

什麼是socket

  所謂socket通常也稱作"套接字",應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求。以J2SDK-1.3爲例,Socket和ServerSocket類庫位於java .net包中。ServerSocket用於服務器端,Socket是建立網絡連接時使用的。在連接成功時,應用程序兩端都會產生一個Socket實例,操作這個實例,完成所需的會話。對於一個網絡連接來說,套接字是平等的,並沒有差別,不因爲在服務器端或在客戶端而產生不同級別。

重要的Socket API

  重要的Socket API:java .net.Socket繼承於java.lang.Object,有八個構造器,其方法並不多,下面介紹使用最頻繁的三個方法,其它方法大家可以見JDK-1.3文檔。  1、Accept方法用於產生"阻塞",直到接受到一個連接,並且返回一個客戶端的Socket對象實例。"阻塞"是一個術語,它使程序運行暫時"停留"在這個地方,直到一個會話產生,然後程序繼續;通常"阻塞"是由循環產生的。  2、getInputStream方法獲得網絡連接輸入,同時返回一個InputStream對象實例。  3、getOutputStream方法連接的另一端將得到輸入,同時返回一個OutputStream對象實例。注意:其中getInputStream和getOutputStream方法均可能會產生一個IOException,它必須被捕獲,因爲它們返回的流對象,通常都會被另一個流對象使用。

SOCKET連接過程

  根據連接啓動的方式以及本地套接字要連接的目標,套接字之間的連接過程可以分爲三個步驟:服務器監聽,客戶端請求,連接確認。  

服務器監聽:是服務器端套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態,實時監控網絡狀態。  

客戶端請求:是指由客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。爲此,客戶端的套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址端口號,然後就向服務器端套接字提出連接請求。  

連接確認:是指當服務器端套接字監聽到或者說接收到客戶端套接字的連接請求,它就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述發給客戶端,一旦客戶端確認了此描述,連接就建立好了。而服務器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連接請求。

下面以一個服務器和客戶端例子說明Socket的使用:

1、服務器端:

創建步驟:

1.1、指定端口實例化一個ServerSocket

1.2、調用ServerSocket的accept()在等待連續期間造成阻塞

1.3、獲取底層Socket的流進行讀寫操作

1.4、將數據庫封裝成流

1.5、對Socket進行讀寫

1.6、關閉打開的流和Socket

服務端代碼如下:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			ServerSocket serverSocket = new ServerSocket(54323);
			while (true) {
				Socket client = serverSocket.accept();
				try {
					BufferedReader read = new BufferedReader(
							new InputStreamReader(client.getInputStream()));
					String str = read.readLine();
					System.out.println("read-->" + str);

					PrintWriter write = new PrintWriter(new BufferedWriter(
							new OutputStreamWriter(client.getOutputStream())),
							true);
					write.println("server message");
					
					read.close();
					write.close();
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
					e.printStackTrace();
				}
				finally{
					client.close();
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println(e.getMessage());
		}
	}
	public static void  main(String a[]) {
		Thread ServerThread = new Thread(new Server());
		ServerThread.start();
	}

}

2、客戶端

創建步驟:

2.1、通過IP地址和端口實例化Socket,請求連接服務器

2.2、獲取Socket上的流進行讀寫

2.3、把數據流包裝進BufferedReader/PrintWriter的實例

2.4、對Socket進行讀寫操作

2.5、關閉打開的流於Socket

客戶端代碼如下(xml文件就不再給出了):

package com.ideal.socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class Net_SocketClientActivity extends Activity {
	private TextView mTextView = null;

	private EditText mEditText = null;

	private Button mButton = null;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		mButton = (Button) findViewById(R.id.Button01);

		mTextView = (TextView) findViewById(R.id.TextView01);

		mEditText = (EditText) findViewById(R.id.EditText01);

		mButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) { 
				// TODO Auto-generated method stub
				Socket socket = null;
				String message = mEditText.getText().toString() + "\r\n";
				try {
					socket = new Socket("172.31.100.50", 54323);

					PrintWriter write = new PrintWriter(new BufferedWriter(
							new OutputStreamWriter(socket.getOutputStream())),
							true);
					write.println(message);

					BufferedReader read = new BufferedReader(
							new InputStreamReader(socket.getInputStream()));
					String msg = read.readLine();
					if(msg!=null){
						mTextView.setText(msg);
					}else {
						mTextView.setText("error");
					}
					write.close();
					read.close();
					socket.close();
				} catch (Exception e) {
					// TODO: handle exception
					System.out.println(e.getMessage());
				}
			}
		});
	}
}

3、針對上面的客戶端與服務器端,需要注意的地方

3.1、服務器端和客戶端在同一個局域網才能使用

3.2、

socket = new Socket("172.31.100.50", 54323);

上面的ip地址並非Internet IP ,我是使用了下面的IPv4 地址:

另,會出現端口問題,如果你的端口(如上面的54323)被佔用了,那麼會出現如下情況:

解決方法:

一:更改服務器的端口號;

二:關閉佔用當前端口的進程

下邊介紹第二種方法

1.首先進入命令行 查看端口是否被佔用  

使用命令: netstat -ano

2.查看該PID爲 54323 的進程

使用命令:tasklist|findstr "54323"

然後可直接退出該進程,或者到任務管理器關閉掉該進程。


4、看下正常運行的結果:

客戶端:

服務器端:

eclipse中Console窗口查看



CMD命令窗口查看


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章