Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發筆記(一百一十一)聊天室中的Socket通信

Android開發筆記(一百一十一)聊天室中的Socket通信

編輯:關於Android編程

Socket通信

基本概念

對於程序開發來說,網絡通信的基礎就是Socket,但因為是基礎,所以用起來不容易,今天我們就來談談Socket通信。計算機網絡有個大名鼎鼎的TCP/IP協議,普通用戶在電腦上設置本地連接的ip時,便經常看到下圖的彈窗,注意紅框部分已經很好地描述了TCP/IP協議的作用。
\


TCP/IP是個協議組,它分為三個層次:網絡層、傳輸層和應用層:
網絡層包括:IP協議、ICMP協議、ARP協議、RARP協議和BOOTP協議。
傳輸層包括:TCP協議、UDP協議。
應用層包括:HTTP、FTP、TELNET、SMTP、DNS等協議。
之前我們提到的網絡編程,其實都是應用層方面的http或ftp編程;而socket屬於傳輸層的技術,它的api實現TCP協議後即可用於http通信,實現UDP協議後即可用於ftp通信,當然也可以直接在底層進行點對點通信,比如即時通信軟件(QQ、微信)這樣就是。


扯遠了,言歸正傳,java的socket編程主要使用Socket和ServerSocket兩個類,下面是相關類的使用說明。


Socket

Socket是最常用的,客戶端和服務端都要用到,它描述了兩邊對套接字(即Socket)處理的一般行為,主要方法說明如下:
connect : 連接指定ip和端口。該方法用於客戶端連接服務端。
getInputStream : 獲取輸入流。即自己收到對方發過來的數據。
getOutputStream : 獲取輸入流。即自己向對方發送的數據。
getInetAddress : 獲取網絡地址對象。該對象是一個InetAddress實例。
isConnected : 判斷socket是否連上。
isClosed : 判斷socket是否關閉。
close : 關閉socket。


ServerSocket

ServerSocket僅用於服務端,它在運行時不停地偵聽指定端口,主要方法說明如下:
構造函數 : 指定偵聽哪個端口。
accept : 開始接收客戶端的連接。有客戶端連上時就返回一個Socket對象,若要持續偵聽連接,得在循環中調用該函數。
getInetAddress : 獲取網絡地址對象。該對象是一個InetAddress實例。
isClosed : 判斷socket服務器是否關閉。
close : 關閉socket服務器。


InetAddress

InetAddress是對網絡地址的一個封裝,主要方法說明如下:
getByName : 根據主機ip/名稱獲取InetAddress對象。
getHostAddress : 獲取主機的ip地址。
getHostName : 獲取主機的名稱。
isReachable : 判斷該地址是否可到達,即是否連通。


聊天室應用

實現原理

Socket在app開發中主要用於聊天/即時通信,因為涉及到客戶端與服務端的交互,所以流程稍微復雜。首先要劃分聊天業務的功能點,以QQ為例,我們平常看到的是三種頁面:登錄頁面、好友列表頁面、聊天頁面。因此,對應的Socket功能也分為三類:
登錄/注銷:登錄操作對應建立Socket連接,而注銷操作對應斷開Socket連接。
獲取好友列表:與Socket有關的是獲取當前在線的好友列表,客戶端到服務端查詢當前已建立Socket連接的好友列表。
發送消息/接收消息:發送/接收消息對應的是Socket的數據傳輸,發送消息操作是客戶端A向服務端發送Socket數據,接收消息操作是服務端將收到的A消息向客戶端B發送Socket數據。


其次在app端需要實現以下功能:
1、至少三個頁面:登錄頁面、好友列表頁面、聊天頁面;
2、一個用於Socket通信的線程。由於在app運行過程中都要保持Socket連接,因此該Socket線程要放在自定義的Application類中。
3、頁面向Socket線程發送消息的機制,用於登錄請求、注銷請求、獲取好友列表請求、發送消息等等。主線程與子線程通信,我們這裡采用Handler+Message機制來處理,有關該機制的使用說明參見《Android開發筆記(四十八)Thread類實現多線程》。
4、Socket線程向頁面發送消息的機制,用於返回好友列表、接收消息等等。因為返回消息會分發到不同的頁面,采用Handler機制有困難,所以這裡我們采用Broadcast廣播來處理,在好友列表頁面和聊天頁面各注冊一個廣播接收器,用於根據服務器返回數據刷新UI。有關Broadcast及其接收器的使用說明參見《Android開發筆記(四十二)Broadcast的生命周期》。


然後在服務端啟動Socket服務器,要實現的功能有:
1、定義一個Socket連接的隊列,用於保存當前連上的Socket請求;
2、循環偵聽指定端口,一旦有新連接進來,則將該連接加入Socket隊列,並啟動新線程為該連接服務;
3、每個服務線程持續從Socket中讀取客戶端發過來的數據,並對不同請求做相應的處理:
a、如果是登錄請求,則標識該Socket連接的用戶昵稱、設備編號、登錄時間等信息;
b、如果是注銷請求,則斷開Socket連接,並從Socket隊列中移除該連接;
c、如果是獲取好友列表請求,則遍歷Socket隊列,封裝好友列表數據並返回;
d、如果是發送消息請求,則根據好友的設備編號到Socket隊列中查找對應的Socket連接,並向該連接返回消息內容;


最後還要定義一下服務端與客戶端之間傳輸消息的格式,按慣例消息包分為包頭與包體兩塊,包頭用於標識操作類型、操作對象、操作時間等基本要素,而包體用於存放具體的消息內容(如好友列表、消息文本等等)。demo工程為簡單起見,就不用xml或json等標准格式,直接用分隔符劃分包頭與包體,以及包頭內部的各元素。


效果截圖

博主在測試時,模擬器上開了一個app,登錄名稱是“在水一方”,真機上開了一個app,登錄名稱是“振興中華”,兩個app連的都是電腦上的Socket服務,從而模擬真實的聊天室環境。登錄頁面與好友列表頁面比較簡單,就不再截圖了,截的都是聊天窗口頁面。為了做得更逼真,中間消息窗口采用對方消息靠左對齊,我方消息靠右對齊的布局,並給雙方消息著不同的背景色。具體截圖如下,左側圖片是真機截圖,右側圖片是模擬器截圖。
\\
\\
\\


代碼示例

app端

幾個注意點:
1、自定義Application類需要采用單例模式,確保Socket線程的唯一性,詳細原因參見《Android開發筆記(八十九)單例模式》。
2、Socket數據包不可直接用換行符“\n”做分隔符,因為在Socket通信中,換行符表示該數據包結束了,所以加了一個換行符,原來一個數據包就變成了兩個數據包。正因如此,用戶聊天的消息文本中若有換行符,則要先進行轉義後才能發給Socket傳輸。
3、如果廣播接收器在代碼中動態注冊,則不會收到Socket線程發出的廣播消息;只有在AndroidManifest.xml中對接收器做靜態注冊,才能收到Socket線程發出的廣播消息,具體原因不明,可能與線程有關。


下面是自定義Application類的代碼:
import com.example.exmsocket.thread.ClientThread;
import com.example.exmsocket.util.DateUtil;

import android.app.Application;
import android.os.Build;
import android.os.Message;
import android.util.Log;

public class MainApplication extends Application {
	private static final String TAG = "MainApplication";

	private static MainApplication mApp;
	private String mNickName;
	private ClientThread mClientThread;

	public static MainApplication getInstance() {
		return mApp;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		mApp = this;
		mClientThread = new ClientThread(mApp);
		new Thread(mClientThread).start();
	}
	
	public void sendAction(String action, String otherId, String msgText) {
		String content = String.format("%s,%s,%s,%s,%s%s%s\r\n", 
				action, Build.SERIAL, getNickName(), DateUtil.getNowTime(), 
				otherId, ClientThread.SPLIT_LINE, msgText);
		Log.d(TAG, "sendAction : " + content);
		Message msg = Message.obtain();
		msg.obj = content;
		if (mClientThread==null || mClientThread.mRecvHandler==null) {
			Log.d(TAG, "mClientThread or its mRecvHandler is null");
		} else {
			mClientThread.mRecvHandler.sendMessage(msg);
		}
	}
	
	public void setNickName(String nickName) {
		mApp.mNickName = nickName;
	}
	
	public String getNickName() {
		return mApp.mNickName;
	}
	
}


下面是登錄頁面的代碼:
import com.example.exmsocket.thread.ClientThread;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {
	private static final String TAG = "MainActivity";

    private EditText et_name;
    private Button btn_ok;
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		et_name = (EditText) findViewById(R.id.et_name);
        btn_ok = (Button) findViewById(R.id.btn_ok);
        btn_ok.setOnClickListener(this);
	}
	
	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_ok) {
			String nickName = et_name.getText().toString().trim();
			if (nickName.length() <= 0) {
				Toast.makeText(this, "請輸入您的昵稱", Toast.LENGTH_SHORT).show();
			} else {
				MainApplication.getInstance().setNickName(nickName);
				MainApplication.getInstance().sendAction(ClientThread.LOGIN, "", "");
				Intent intent = new Intent(this, FriendListActivity.class);
				startActivity(intent);
				finish();
			}
		}
	}
}


下面是好友列表頁面的代碼:
import java.util.ArrayList;

import com.example.exmsocket.adapter.Friend;
import com.example.exmsocket.adapter.FriendListAdapter;
import com.example.exmsocket.thread.ClientThread;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class FriendListActivity extends Activity implements OnClickListener {
	private static final String TAG = "FriendListActivity";

    private static Context mContext;
    private static ListView lv_friend;
    private Button btn_refresh;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);
        mContext = getApplicationContext();
        lv_friend = (ListView) findViewById(R.id.lv_friend);
        btn_refresh = (Button) findViewById(R.id.btn_refresh);
        btn_refresh.setOnClickListener(this);
    }
    
    @Override
    protected void onResume() {
		mHandler.postDelayed(mRefresh, 500);
    	super.onResume();
    }
    
    @Override
    protected void onDestroy() {
    	MainApplication.getInstance().sendAction(ClientThread.LOGOUT, "", "");
    	super.onDestroy();
    }
    
    private Handler mHandler = new Handler();
    private Runnable mRefresh = new Runnable() {
		@Override
		public void run() {
	        MainApplication.getInstance().sendAction(ClientThread.GETLIST, "", "");
		}
    };

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_refresh) {
			mHandler.post(mRefresh);
		}
	}
    
	public static class GetListReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent != null) {
				Log.d(TAG, "onReceive");
				String content = intent.getStringExtra(ClientThread.CONTENT);
				if (mContext != null && content != null && content.length() > 0) {
					int pos = content.indexOf(ClientThread.SPLIT_LINE);
					String head = content.substring(0, pos);
					String body = content.substring(pos + 1);
					String[] splitArray = head.split(ClientThread.SPLIT_ITEM);
					if (splitArray[0].equals(ClientThread.GETLIST)) {
						String[] bodyArray = body.split("\\|");
						ArrayList friendList = new ArrayList();
						for (int i = 0; i < bodyArray.length; i++) {
							String[] itemArray = bodyArray[i].split(ClientThread.SPLIT_ITEM);
							if (bodyArray[i].length() > 0 && itemArray != null && itemArray.length >= 3) {
								friendList.add(new Friend(itemArray[0], itemArray[1], itemArray[2]));
							}
						}
						if (friendList.size() > 0) {
							FriendListAdapter adapter = new FriendListAdapter(mContext, friendList);
							lv_friend.setAdapter(adapter);
							lv_friend.setOnItemClickListener(adapter);
						}
					} else {
						String hint = String.format("%s\n%s", splitArray[0], body);
						Toast.makeText(mContext, hint, Toast.LENGTH_SHORT).show();
					}
				}
			}
		}
	}

}


下面是聊天頁面的代碼:
import com.example.exmsocket.thread.ClientThread;
import com.example.exmsocket.util.DateUtil;
import com.example.exmsocket.util.MetricsUtil;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class ChatActivity extends Activity implements OnClickListener {
	private static final String TAG = "ChatActivity";

    private static Context mContext;
    private TextView tv_other;
    private EditText et_input;
    private static TextView tv_show;
    private static LinearLayout ll_show;
    private Button btn_send;
    private String mOtherId;
    private static int dip_margin;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        mContext = getApplicationContext();
        tv_other = (TextView) findViewById(R.id.tv_other);
        et_input = (EditText) findViewById(R.id.et_input);
        tv_show = (TextView) findViewById(R.id.tv_show);
        ll_show = (LinearLayout) findViewById(R.id.ll_show);
        btn_send = (Button) findViewById(R.id.btn_send);
        btn_send.setOnClickListener(this);
        
        dip_margin = MetricsUtil.dip2px(mContext, 5);
        Bundle bundle = getIntent().getExtras();
        mOtherId = bundle.getString("otherId", "");
        String desc = String.format("與%s聊天", bundle.getString("otherName", ""));
        tv_other.setText(desc);
    }

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_send) {
			String body = et_input.getText().toString();
			String append = String.format("%s %s\n%s",
					MainApplication.getInstance().getNickName(),
					DateUtil.formatTime(DateUtil.getNowTime()), body);
			appendMsg(Build.SERIAL, append);
            MainApplication.getInstance().sendAction(ClientThread.SENDMSG, mOtherId, body);
            et_input.setText("");
		}
	}
	
	private static void appendMsg(String deviceId, String append) {
		//tv_show.setText(tv_show.getText().toString() + append);
		int gravity = deviceId.equals(Build.SERIAL) ? Gravity.RIGHT : Gravity.LEFT;
		int bg_color = deviceId.equals(Build.SERIAL) ? 0xffccccff : 0xffffcccc;
		LinearLayout ll_append = new LinearLayout(mContext);
		LinearLayout.LayoutParams ll_params = new LinearLayout.LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		ll_params.setMargins(dip_margin, dip_margin, dip_margin, dip_margin);
		ll_append.setLayoutParams(ll_params);
		ll_append.setGravity(gravity);
		
		TextView tv_append = new TextView(mContext);
		tv_append.setText(tv_show.getText().toString() + append);
		tv_append.setTextColor(Color.BLACK);
		LinearLayout.LayoutParams tv_params = new LinearLayout.LayoutParams(
				LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
		tv_append.setLayoutParams(tv_params);
		tv_append.setBackgroundColor(bg_color);
		ll_append.addView(tv_append);

		ll_show.addView(ll_append);
	}

	public static class RecvMsgReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent != null) {
				Log.d(TAG, "onReceive");
				String content = intent.getStringExtra(ClientThread.CONTENT);
				if (mContext != null && content != null && content.length() > 0) {
					int pos = content.indexOf(ClientThread.SPLIT_LINE);
					String head = content.substring(0, pos);
					String body = content.substring(pos + 1);
					String[] splitArray = head.split(ClientThread.SPLIT_ITEM);
					if (splitArray[0].equals(ClientThread.RECVMSG)) {
						String append = String.format("%s %s\n%s",
								splitArray[2], DateUtil.formatTime(splitArray[3]), body);
						appendMsg(splitArray[1], append);
					} else {
						String hint = String.format("%s\n%s", splitArray[0], body);
						Toast.makeText(mContext, hint, Toast.LENGTH_SHORT).show();
					}
				}
			}
		}
	}

}


下面是Socket線程的代碼:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
  
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
  
public class ClientThread implements Runnable {
	private static final String TAG = "ClientThread";
	private static final String SOCKET_IP = "192.168.0.212";  // 模擬器使用
	//private static final String SOCKET_IP = "192.168.253.1";  // 真機使用
	private static final int SOCKET_PORT = 52000;
	public static String ACTION_RECV_MSG = "com.example.exmsocket.RECV_MSG";
	public static String ACTION_GET_LIST = "com.example.exmsocket.GET_LIST";
	public static String CONTENT = "CONTENT";
	public static String SPLIT_LINE = "|";
	public static String SPLIT_ITEM = ",";

	public static String LOGIN = "LOGIN";
	public static String LOGOUT = "LOGOUT";
	public static String SENDMSG = "SENDMSG";
	public static String RECVMSG = "RECVMSG";
	public static String GETLIST = "GETLIST";

    private Context mContext;
    private Socket mSocket;
    // 定義接收UI線程的Handler對象
    public Handler mRecvHandler;
    private BufferedReader mReader = null;
    private OutputStream mWriter = null;
    
    public ClientThread(Context context) {
    	mContext = context;
    }
  
    @Override  
    public void run() {
    	mSocket = new Socket();
        try {
        	mSocket.connect(new InetSocketAddress(SOCKET_IP, SOCKET_PORT), 3000);
            mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
            mWriter = mSocket.getOutputStream();
            // 啟動一條子線程來讀取服務器相應的數據  
            new Thread() {
                @Override  
                public void run() {
                    String content = null;
                    try {
                        while ((content = mReader.readLine()) != null) {
                            // 讀取到來自服務器的數據之後,發送消息通知
                        	ClientThread.this.notify(0, content);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        ClientThread.this.notify(97, e.getMessage());
                    }
                }
            }.start();
            Looper.prepare();
            mRecvHandler = new Handler() {
                @Override  
                public void handleMessage(Message msg) {
					// 接收到UI線程的中用戶輸入的數據
					try {
						mWriter.write(msg.obj.toString().getBytes("utf8"));
					} catch (Exception e) {
						e.printStackTrace();
						ClientThread.this.notify(98, e.getMessage());
					}
                }
            };
            Looper.loop();
        } catch (Exception e) {
        	e.printStackTrace();
        	notify(99, e.getMessage());
        }
    }
    
    private void notify(int type, String message) {
    	if (type == 99) {
    		String content = String.format("%s%s%s%s", "ERROR", SPLIT_ITEM, SPLIT_LINE, message);
			Intent intent1 = new Intent(ACTION_RECV_MSG);
			intent1.putExtra(CONTENT, content);
			mContext.sendBroadcast(intent1);
			Intent intent2 = new Intent(ACTION_GET_LIST);
			intent2.putExtra(CONTENT, content);
			mContext.sendBroadcast(intent2);
    	} else {
			int pos = message.indexOf(SPLIT_LINE);
			String head = message.substring(0, pos-1);
			String[] splitArray = head.split(SPLIT_ITEM);
			String action = "";
			if (splitArray[0].equals(RECVMSG)) {
				action = ACTION_RECV_MSG;
			} else if (splitArray[0].equals(GETLIST)) {
				action = ACTION_GET_LIST;
			}
	    	Log.d(TAG, "action="+action+", message="+message);
			Intent intent = new Intent(action);
			intent.putExtra(CONTENT, message);
			mContext.sendBroadcast(intent);
    	}
    }
    
}


服務端

下面是服務端的主程序代碼:
import java.net.ServerSocket;
import java.util.ArrayList;

public class ChatServer {
	private static final int SOCKET_PORT = 52000;
	public static ArrayList mSocketList = new ArrayList();

	private void initServer() {
		try {
			// 創建一個ServerSocket,用於監聽客戶端Socket的連接請求
			ServerSocket server = new ServerSocket(SOCKET_PORT);
			while (true) {
				// 每當接收到客戶端的Socket請求,服務器端也相應的創建一個Socket
				SocketBean socket = new SocketBean(DateUtil.getTimeId(), server.accept());
				mSocketList.add(socket);
				// 每連接一個客戶端,啟動一個ServerThread線程為該客戶端服務
				new Thread(new ServerThread(socket)).start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		ChatServer server = new ChatServer();
		server.initServer();
	}
}


下面是服務線程的代碼:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;

public class ServerThread implements Runnable {

	private SocketBean mSocket = null;
	private BufferedReader mReader = null;

	public ServerThread(SocketBean mSocket) throws IOException {
		this.mSocket = mSocket;
		mReader = new BufferedReader(new InputStreamReader(
				mSocket.socket.getInputStream()));
	}

	@Override
	public void run() {
		try {
			String content = null;
			// 循環不斷地從Socket中讀取客戶端發送過來的數據
			while ((content = mReader.readLine()) != null) {
				System.out.println("content="+content);
				int pos = content.indexOf("|");
				// 包頭格式為:動作名稱|設備編號|昵稱|時間|對方設備編號
				String head = content.substring(0, pos);
				String body = content.substring(pos+1);
				String[] splitArray = head.split(",");
				String action = splitArray[0];
				System.out.println("action="+action);
				if (action.equals("LOGIN")) {
					login(splitArray[1], splitArray[2], splitArray[3]);
				} else if (action.equals("LOGOUT")) {
					logout(splitArray[1]);
					break;
				} else if (action.equals("SENDMSG")) {
					sendmsg(splitArray[2], splitArray[4], splitArray[1], body);
				} else if (action.equals("GETLIST")) {
					getlist(splitArray[1]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void login(String deviceId, String nickName, String loginTime) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.id.equals(mSocket.id)) {
				item.deviceId = deviceId;
				item.nickName = nickName;
				item.loginTime = loginTime;
				ChatServer.mSocketList.set(i, item);
				break;
			}
		}
	}
	
	private String getFriend() {
		String friends = "GETLIST,";
		for (SocketBean item : ChatServer.mSocketList) {
			if (item.deviceId!=null && item.deviceId.length()>0) {
				String friend = String.format("|%s,%s,%s", item.deviceId, item.nickName, item.loginTime);
				friends += friend;
			}
		}
		return friends;
	}
	
	private void getlist(String deviceId) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {
				PrintStream printStream = new PrintStream(item.socket.getOutputStream());
				printStream.println(getFriend());
				break;
			}
		}
	}
	
	private void logout(String deviceId) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.id.equals(mSocket.id) && item.deviceId.equals(deviceId)) {
				PrintStream printStream = new PrintStream(item.socket.getOutputStream());
				printStream.println("LOGOUT,|");
				item.socket.close();
				ChatServer.mSocketList.remove(i);
				break;
			}
		}
	}

	private void sendmsg(String otherName, String otherId, String selfId, String message) throws IOException {
		for (int i=0; i<ChatServer.mSocketList.size(); i++) {
			SocketBean item = ChatServer.mSocketList.get(i);
			if (item.deviceId.equals(otherId)) {
				String content = String.format("%s,%s,%s,%s|%s", 
						"RECVMSG", selfId, otherName, DateUtil.getNowTime(), message);
				PrintStream printStream = new PrintStream(item.socket.getOutputStream());
				printStream.println(content);
				break;
			}
		}
	}

}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved