目錄:
一、效果圖
二、原代碼分享
三、代碼分析
四、總結
一、效果圖如下:
客戶端1: 客戶端2:
二、原代碼分享如下:
1、java代碼只有一個
MainActivity.java

1 package com; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.OutputStream; 7 import java.io.UnsupportedEncodingException; 8 import java.net.ServerSocket; 9 import java.net.Socket; 10 import java.util.ArrayList; 11 12 import android.app.Activity; 13 import android.os.Bundle; 14 import android.os.Handler; 15 import android.os.Message; 16 import android.view.View; 17 import android.view.View.OnClickListener; 18 import android.widget.Button; 19 import android.widget.CheckBox; 20 import android.widget.CompoundButton; 21 import android.widget.CompoundButton.OnCheckedChangeListener; 22 import android.widget.EditText; 23 import android.widget.TextView; 24 25 import com.example.androidsockettest.R; 26 27 public class MainActivity extends Activity{ 28 29 private Button button_send = null; 30 private EditText et_ip = null; 31 private EditText et_port = null; 32 private EditText et_conent = null; 33 private TextView tv_history = null; 34 private CheckBox checkBoxSwitch = null; 35 private static int defaultPort = 8888; 36 public static ArrayList<Socket> socketList=new ArrayList<Socket>(); 37 38 private OutputStream out=null; 39 private Handler handler = null; 40 private Socket s = null; 41 String tag = "chatRoom"; 42 private BufferedReader buRead = null; 43 44 private final int UPDATE_HISTORY_CONTENT = 0; 45 private final int UPDATE_INPUT_CONTENT = 1; 46 47 @Override 48 protected void onCreate(Bundle savedInstanceState) { 49 // TODO Auto-generated method stub 50 super.onCreate(savedInstanceState); 51 setContentView(R.layout.main_activity); 52 53 init(); 54 55 configure(); 56 57 serverStart(); 58 } 59 60 @Override 61 protected void onDestroy() { 62 // TODO Auto-generated method stub 63 super.onDestroy(); 64 } 65 66 67 public void init() 68 { 69 button_send = (Button)findViewById(R.id.button_send); 70 et_ip = (EditText)findViewById(R.id.editText_ip); 71 et_port = (EditText)findViewById(R.id.EditText_port); 72 et_conent = (EditText)findViewById(R.id.EditText_content); 73 tv_history = (TextView)findViewById(R.id.textView_history_content); 74 checkBoxSwitch = (CheckBox)findViewById(R.id.checkBox_server_start); 75 } 76 77 78 public void configure() 79 { 80 button_send.setOnClickListener(new OnClickListener() { 81 82 @Override 83 public void onClick(View v) { 84 // TODO Auto-generated method stub 85 try { 86 String content = et_conent.getText().toString();//讀取用戶輸入文本 87 88 if(out == null) 89 { 90 CommonUtils.LogWuwei(tag,"the fucking out is null"); 91 return; 92 } 93 94 out.write((content+"\n").getBytes("utf-8"));//寫入socket 95 96 String history_content = tv_history.getText().toString(); 97 history_content+="你說:"+et_conent.getText()+"\n"; 98 99 100 Message msg = new Message(); 101 msg.what = UPDATE_HISTORY_CONTENT; 102 msg.obj = history_content; 103 handler.sendMessage(msg); 104 105 msg = new Message(); 106 msg.what = UPDATE_INPUT_CONTENT; 107 msg.obj = ""; 108 handler.sendMessage(msg); 109 110 111 CommonUtils.LogWuwei(tag, "send success"); 112 } catch (UnsupportedEncodingException e) { 113 // TODO Auto-generated catch block 114 e.printStackTrace(); 115 CommonUtils.LogWuwei(tag, "send failed "+e.getMessage()); 116 } catch (IOException e) { 117 // TODO Auto-generated catch block 118 e.printStackTrace(); 119 CommonUtils.LogWuwei(tag, "send failed "+e.getMessage()); 120 } 121 } 122 }); 123 124 125 checkBoxSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() { 126 127 @Override 128 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 129 // TODO Auto-generated method stub 130 if(isChecked) 131 { 132 CommonUtils.LogWuwei(tag, "clientStart"); 133 clientStart(); 134 } 135 else 136 { 137 CommonUtils.LogWuwei(tag, "clientStop"); 138 clientStop(); 139 } 140 } 141 }); 142 143 144 handler = new Handler() 145 { 146 @Override 147 public void handleMessage(Message msg) { 148 // TODO Auto-generated method stub 149 super.handleMessage(msg); 150 switch (msg.what) 151 { 152 case UPDATE_HISTORY_CONTENT: 153 CommonUtils.LogWuwei(tag, "更新歷史記錄"+msg.obj); 154 tv_history.setText((String)msg.obj); 155 break; 156 157 case UPDATE_INPUT_CONTENT: 158 CommonUtils.LogWuwei(tag, "清空輸入記錄"); 159 et_conent.setText("");//清空文本 160 break; 161 } 162 } 163 }; 164 165 } 166 167 168 public void serverStart() 169 { 170 try { 171 172 final ServerSocket ss = new ServerSocket(defaultPort); 173 174 CommonUtils.LogWuwei(tag, "on serverStart"); 175 176 new Thread() 177 { 178 public void run() 179 { 180 while(true) 181 { 182 try { 183 CommonUtils.LogWuwei(tag, "on serverStart: ready to accept"); 184 s=ss.accept(); 185 socketList.add(s); 186 buRead = new BufferedReader(new InputStreamReader(s.getInputStream(), "utf-8")); 187 188 String receive_content = null; 189 while ((receive_content=readFromClient())!=null) { 190 CommonUtils.LogWuwei(tag,"客戶端說:"+receive_content); 191 192 String history_content = tv_history.getText().toString(); 193 history_content+=s.getInetAddress()+"說:"+receive_content+"\n"; 194 195 Message msg = new Message(); 196 msg.what = UPDATE_HISTORY_CONTENT; 197 msg.obj = history_content; 198 handler.sendMessage(msg); 199 200 201 for (Socket ss:socketList) 202 { 203 OutputStream out=ss.getOutputStream(); 204 out.write(("[服務器已經收到消息]"+"\n").getBytes("utf-8")); 205 } 206 } 207 208 209 } catch (UnsupportedEncodingException e) { 210 // TODO Auto-generated catch block 211 e.printStackTrace(); 212 } catch (IOException e) { 213 // TODO Auto-generated catch block 214 e.printStackTrace(); 215 } 216 217 } 218 } 219 }.start(); 220 221 } catch (IOException e) { 222 // TODO Auto-generated catch block 223 e.printStackTrace(); 224 } 225 226 } 227 228 229 private String readFromClient(){ 230 try { 231 return buRead.readLine(); 232 } catch (Exception e) { 233 //刪除此Socket 234 socketList.remove(s); 235 } 236 return null; 237 } 238 239 240 public void clientStart() 241 { 242 new Thread(new Runnable() { 243 244 @Override 245 public void run() { 246 try { 247 String ip = et_ip.getText().toString(); 248 String port = et_port.getText().toString(); 249 250 if(!port.equals("") && port != null) 251 { 252 s=new Socket(ip, defaultPort); 253 } 254 else 255 { 256 s=new Socket(ip, Integer.parseInt(port)); 257 } 258 259 out=s.getOutputStream(); 260 CommonUtils.LogWuwei(tag, "clientStart success"); 261 262 } catch (IOException e) { 263 e.printStackTrace(); 264 CommonUtils.LogWuwei(tag, "clientStart failed "+e.getMessage()); 265 } 266 } 267 }).start(); 268 269 270 } 271 272 273 public void clientStop() 274 { 275 try { 276 if(s != null) 277 s.close(); 278 if(out != null) 279 out.close(); 280 281 } catch (IOException e) { 282 // TODO Auto-generated catch block 283 e.printStackTrace(); 284 } 285 286 287 } 288 289 }
2、xml文件也是只有一個
main_activity.xml

1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" > 5 6 <EditText 7 android:id="@+id/editText_ip" 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:layout_toRightOf="@+id/TextView_ip_tips" 11 android:layout_marginRight="15dp" 12 android:text="192.168.1.232" 13 android:ems="10"/> 14 15 <TextView 16 android:id="@+id/TextView_ip_tips" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:layout_alignParentLeft="true" 20 android:layout_marginTop="16dp" 21 android:text="接受IP:" /> 22 23 <EditText 24 android:id="@+id/EditText_port" 25 android:layout_width="wrap_content" 26 android:layout_height="wrap_content" 27 android:layout_toRightOf="@+id/textView_port_tips" 28 android:layout_below="@+id/editText_ip" 29 android:layout_marginTop="16dp" 30 android:ems="10" 31 android:text="8888" 32 android:inputType="number" > 33 34 <requestFocus /> 35 </EditText> 36 37 <TextView 38 android:id="@+id/textView_port_tips" 39 android:layout_width="wrap_content" 40 android:layout_height="wrap_content" 41 android:layout_alignBottom="@+id/EditText_port" 42 android:layout_alignParentLeft="true" 43 android:text="輸入端口號:" /> 44 45 <TextView 46 android:id="@+id/textView_history_content" 47 android:layout_width="match_parent" 48 android:layout_height="350dp" 49 android:layout_below="@+id/checkBox_server_start" /> 50 51 52 53 <Button 54 android:id="@+id/button_send" 55 android:layout_width="wrap_content" 56 android:layout_height="wrap_content" 57 android:layout_toRightOf="@+id/EditText_content" 58 android:layout_alignParentBottom="true" 59 android:text="發送" /> 60 61 <EditText 62 android:id="@+id/EditText_content" 63 android:layout_width="wrap_content" 64 android:layout_height="wrap_content" 65 android:layout_alignParentLeft="true" 66 android:layout_alignParentBottom="true" 67 android:ems="10" /> 68 69 <CheckBox 70 android:id="@+id/checkBox_server_start" 71 android:layout_width="wrap_content" 72 android:layout_height="wrap_content" 73 android:layout_alignParentLeft="true" 74 android:layout_below="@+id/EditText_port" 75 android:layout_marginLeft="24dp" 76 android:checked="false" 77 android:text="開啟發送模式" /> 78 79 </RelativeLayout>
三、代碼分析
流程分析:
1、服務端
程序開啟的時候,執行serverStart()方法,將自身做為serverSocket,端口號為8888,做為socket的服務器跑起來;
在循環中,通過帶有阻塞特性的accept函數等待連接,如果有連接,通過accept函數得到套接字s,然后通過s的getInputStream()方法得到輸入流(也就是對方發送的內容),同事也從s的getInetAddress方法得到對方的ip地址;這樣一來就讀到了兩個重要信息 ① ip地址 ②發送過來的內容
2、客戶端
在通過設置edittext內容,配置得到對方的IP地址和端口號,如果選中"開啟發送模式",然后創建套件字s,通過套接字的getOutputStream()方法得到可寫流out;
“發送”按鈕的回調函數是用來通過可寫流-寫入-套接字(寫入內容為用戶輸入的文本)
這樣一來,程序基本ok了,然后運行在兩部手機上,即可實現基於socket的網絡聊天。
四、總結
參考連接:
1、 http://mobile.51cto.com/android-386691.htm
2、http://blog.csdn.net/conowen/article/details/7313671
3、http://www.cnblogs.com/harrisonpc/archive/2011/03/31/2001565.html
socket簡單通信的幾個關鍵點:
1、如果要實現接受消息功能,需要本身做為服務端跑起來,同時得到可讀流。關鍵點:serverSocket、getIputStream
2、如果要實現消息發送功能,需要本身創建套接字,並得到可寫流,同時設置要發送到的ip和端口號。關鍵點:socket、getOutputStream、對方IP、對方Port
That's All
沒找到在隨筆里如何添加附件,工程附件大家去網盤下載去吧。http://pan.baidu.com/s/1o6vA8sU