一、概述
網絡通信無論在手機還是其他設備上都應用得非常廣泛,因此掌握網絡編程是非常有必要的,而我覺得socket編程是網絡編程的基礎。在進入正題之前,先介紹幾點網絡知識,一:socket編程有分TCP和UDP兩種,TCP是基於連接的,而UDP是無連接的;二:一個TCP連接包括了輸入和輸出兩條獨立的路徑;三:服務器必須先運行然后客戶端才能與它進行通信。四:客戶端與服務器所使用的編碼方式要相同,否則會出現亂碼。下面的實現中為了講解的方便,並沒有采用多線程的方法,因此通信過程中會阻塞UI線程,而且只涉及了單向通信(客戶端-->服務器),完善的程序(多線程,雙向通信)會在提高篇再講解。
二、要求
熟悉socket編程。
三、實現
新建工程MyClient,修改/res/layout/main.xml文件,在里面添加一個EditText和兩個Button,完整的main.xml文件如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <EditText
8 android:id="@+id/edittext"
9 android:layout_width="fill_parent"
10 android:layout_height="wrap_content"
11 android:hint="請輸入要發送的內容"
12 />
13
14 <Button
15 android:id="@+id/connectbutton"
16 android:layout_width="fill_parent"
17 android:layout_height="wrap_content"
18 android:text="連接"
19 />
20
21 <Button
22 android:id="@+id/sendbutton"
23 android:layout_width="fill_parent"
24 android:layout_height="wrap_content"
25 android:text="發送"
26 />
27
28
29 </LinearLayout>
接着,修改MyClientActivity.java文件,定義一個socket對象和一個OutputStream對象(用於發送數據),完整的內容如下:
1 package com.nan.client;
2
3 import java.io.IOException;
4 import java.io.OutputStream;
5 import java.io.UnsupportedEncodingException;
6 import java.net.Socket;
7 import java.net.UnknownHostException;
8
9 import android.app.Activity;
10 import android.os.Bundle;
11 import android.view.View;
12 import android.widget.Button;
13 import android.widget.EditText;
14 import android.widget.Toast;
15
16
17 public class MyClientActivity extends Activity
18 {
19 private EditText mEditText = null;
20 private Button connectButton = null;
21 private Button sendButton = null;
22
23 private Socket clientSocket = null;
24 private OutputStream outStream = null;
25
26
27 /** Called when the activity is first created. */
28 @Override
29 public void onCreate(Bundle savedInstanceState)
30 {
31 super.onCreate(savedInstanceState);
32 setContentView(R.layout.main);
33
34 mEditText = (EditText)this.findViewById(R.id.edittext);
35 connectButton = (Button)this.findViewById(R.id.connectbutton);
36 sendButton = (Button)this.findViewById(R.id.sendbutton);
37 sendButton.setEnabled(false);
38
39 //連接按鈕監聽
40 connectButton.setOnClickListener(new View.OnClickListener()
41 {
42
43 @Override
44 public void onClick(View v)
45 {
46 // TODO Auto-generated method stub
47 try
48 {
49 //實例化對象並連接到服務器
50 clientSocket = new Socket("183.41.101.71",8888);
51 }
52 catch (UnknownHostException e)
53 {
54 // TODO Auto-generated catch block
55 e.printStackTrace();
56 }
57 catch (IOException e)
58 {
59 // TODO Auto-generated catch block
60 e.printStackTrace();
61 }
62
63 displayToast("連接成功!");
64
65 connectButton.setEnabled(false);
66 sendButton.setEnabled(true);
67 }
68 });
69
70 //發送數據按鈕監聽
71 sendButton.setOnClickListener(new View.OnClickListener()
72 {
73
74 @Override
75 public void onClick(View v)
76 {
77 // TODO Auto-generated method stub
78 byte[] msgBuffer = null;
79 //獲得EditTex的內容
80 String text = mEditText.getText().toString();
81 try {
82 //字符編碼轉換
83 msgBuffer = text.getBytes("GB2312");
84 } catch (UnsupportedEncodingException e1) {
85 // TODO Auto-generated catch block
86 e1.printStackTrace();
87 }
88
89
90 try {
91 //獲得Socket的輸出流
92 outStream = clientSocket.getOutputStream();
93 } catch (IOException e) {
94 // TODO Auto-generated catch block
95 e.printStackTrace();
96 }
97
98
99 try {
100 //發送數據
101 outStream.write(msgBuffer);
102 } catch (IOException e) {
103 // TODO Auto-generated catch block
104 e.printStackTrace();
105 }
106
107 displayToast("發送成功!");
108 }
109 });
110
111
112 }
113
114 //顯示Toast函數
115 private void displayToast(String s)
116 {
117 Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
118 }
119
120
121 }
接着,新建工程MyServer,同樣修改/res/layout/main.xml文件,如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <TextView
8 android:id="@+id/textview"
9 android:layout_width="fill_parent"
10 android:layout_height="wrap_content"
11 android:textSize="15dip"
12
13 />
14
15 </LinearLayout>
修改MyServerActivity.java文件,比較簡單,代碼中有詳細注釋,如下:
1 package com.nan.server;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.UnsupportedEncodingException;
6 import java.net.ServerSocket;
7 import java.net.Socket;
8
9 import android.app.Activity;
10 import android.os.Bundle;
11 import android.widget.TextView;
12
13
14 public class MyServerActivity extends Activity
15 {
16 private TextView mTextView = null;
17
18 private InputStream mInputStream = null;
19 private Socket clientSocket = null;
20 private ServerSocket mServerSocket = null;
21
22 /** Called when the activity is first created. */
23 @Override
24 public void onCreate(Bundle savedInstanceState)
25 {
26 super.onCreate(savedInstanceState);
27 setContentView(R.layout.main);
28
29 mTextView = (TextView)this.findViewById(R.id.textview);
30
31 try {
32 //實例化ServerSocket對象並設置端口號為8888
33 mServerSocket = new ServerSocket(8888);
34 } catch (IOException e) {
35 // TODO Auto-generated catch block
36 e.printStackTrace();
37 }
38
39 try {
40 //等待客戶端的連接(阻塞)
41 clientSocket = mServerSocket.accept();
42 } catch (IOException e) {
43 // TODO Auto-generated catch block
44 e.printStackTrace();
45 }
46
47 try {
48 //獲得socket的輸入流
49 mInputStream = clientSocket.getInputStream();
50 } catch (IOException e) {
51 // TODO Auto-generated catch block
52 e.printStackTrace();
53 }
54
55 byte[] buf = new byte[512];
56 String str = null;
57
58 try {
59 //讀取輸入的數據(阻塞讀)
60 mInputStream.read(buf);
61 } catch (IOException e) {
62 // TODO Auto-generated catch block
63 e.printStackTrace();
64 }
65
66 try {
67 //字符編碼轉換
68 str = new String(buf, "GB2312").trim();
69 } catch (UnsupportedEncodingException e) {
70 // TODO Auto-generated catch block
71 e.printStackTrace();
72 }
73 //顯示接收到的數據
74 mTextView.setText("收到的數據:"+str);
75
76 }
77
78 }
最后在兩個工程的AndroidMainfest.xml文件中都加入權限:
1 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
到這里,客戶端和服務器的程序都寫好了,在模擬器上運行客戶端程序:

在真機上運行服務器程序:

接着,點擊客戶端“連接”按鈕,輸入一些內容再點擊“發送”按鈕:

此時服務器端的情況如下:

可見成功接收了客戶端發送過來的數據。
