Socket也稱為“套接字”,是網(wǎng)絡通信中的概念,它分為流式套接字和用戶數(shù)據(jù)報套接字兩種,分別對應于網(wǎng)絡的傳輸控制層的TCP和UDP協(xié)議。TCP協(xié)議是面向連接的協(xié)議,提供穩(wěn)定的雙向通信功能,TCP連接的建立需要經過“三次握手”才能生成,為了提供穩(wěn)定的數(shù)據(jù)傳輸功能,其本身提供了超時重傳機制,因此具有很高的穩(wěn)定性;而UDP是無連接的,提供不穩(wěn)定的單向通信功能,當然UDP也可以實現(xiàn)雙向通信功能。在性能上,UDP具有更好的效率,其缺點是不保證數(shù)據(jù)一定能夠正確傳輸,尤其是在網(wǎng)絡擁塞的情況下。
使用Socket來通信,有兩點需要注意,首先需要聲明權限:

其次要注意不能在主線程中訪問網(wǎng)絡,因為這會導致我們的程序無法在Android4.0及其以上的設備中運行,會拋出如下異常:android.os.NetworkOnMainThreadException。而且進行網(wǎng)絡操作很可能是耗時的,如果放在主線程中會影響程序的響應效率,從這方面來說,也不應該在主線程中訪問網(wǎng)絡。實際上通過Socket不僅僅能實現(xiàn)進程間通信,還可以實現(xiàn)設備間的通信,當然前提是這些設備之間的IP地址互相可見。
/*** 客戶端*/
public class TCPClientActivityextends Activityimplements View.OnClickListener {
private static final int MESSAGE_RECEIVE_NEW_MSG =1;
? ? private static final int MESSAGE_SOCKET_CONNECTED =2;
? ? private ButtonmSendButton;
? ? private TextViewmMessageTextView;
? ? private EditTextmMessageEditText;
? ? private PrintWritermPrintWriter;
? ? private SocketmClientSocket;
? ? private HandlermHandler =new Handler() {
@Override
? ? ? ? public void handleMessage(Message msg) {
// super.handleMessage(msg);
? ? ? ? ? ? switch (msg.what) {
case MESSAGE_RECEIVE_NEW_MSG: {
mMessageTextView.setText(mMessageTextView.getText() + (String) msg.obj);
break;
? ? ? ? ? ? ? ? }
case MESSAGE_SOCKET_CONNECTED: {
mSendButton.setEnabled(true);
break;
? ? ? ? ? ? ? ? }
default:
break;
? ? ? ? ? ? }
}
};
? ? @Override
? ? protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activtiy_tcpclient);
? ? ? ? mMessageTextView = findViewById(R.id.msg_container);
? ? ? ? mSendButton = findViewById(R.id.send);
? ? ? ? mSendButton.setOnClickListener(this);
? ? ? ? mMessageEditText = findViewById(R.id.msg);
? ? ? ? Intent service =new Intent(this, TCPServerService.class);
? ? ? ? startService(service);
? ? ? ? new Thread() {
@Override
? ? ? ? ? ? public void run() {
connectTCPServer();
? ? ? ? ? ? }
}.start();
? ? }
@Override
? ? protected void onDestroy() {
super.onDestroy();
? ? ? ? if (mClientSocket !=null) {
try {
mClientSocket.shutdownInput();
? ? ? ? ? ? ? ? mClientSocket.close();
? ? ? ? ? ? }catch (IOException e) {
e.printStackTrace();
? ? ? ? ? ? }
}
}
@Override
? ? public void onClick(View v) {
if (v ==mSendButton) {
final String msg =mMessageEditText.getText().toString();
? ? ? ? ? ? if (!TextUtils.isEmpty(msg) &&mPrintWriter !=null) {
new Thread(new Runnable() {
@Override
? ? ? ? ? ? ? ? ? ? public void run() {
mPrintWriter.println(msg);
? ? ? ? ? ? ? ? ? ? }
}).start();
? ? ? ? ? ? ? ? mMessageEditText.setText("");
? ? ? ? ? ? ? ? String time = formatDateTime(System.currentTimeMillis());
? ? ? ? ? ? ? ? final String showedMsg ="self" + time +":" + msg +"\n";
? ? ? ? ? ? ? ? mMessageTextView.setText(mMessageTextView.getText() + showedMsg);
? ? ? ? ? ? }
}
}
private StringformatDateTime(long time) {
return new SimpleDateFormat("(HH:MM:ss)").format(new Date(time));
? ? }
private void connectTCPServer() {
Socket socket =null;
? ? ? ? while (socket ==null) {
try {
socket =new Socket("localhost", 8688);
? ? ? ? ? ? ? ? mClientSocket = socket;
? ? ? ? ? ? ? ? mPrintWriter =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
? ? ? ? ? ? ? ? mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
? ? ? ? ? ? ? ? System.out.println("connect server success");
? ? ? ? ? ? }catch (IOException e) {
SystemClock.sleep(1000);
? ? ? ? ? ? ? ? System.out.println("connect tcp server failed,retry... ");
? ? ? ? ? ? }
}
try {
//接收服務器端的消息
? ? ? ? ? ? BufferedReader br =new BufferedReader(new InputStreamReader(socket.getInputStream()));
? ? ? ? ? ? while (!TCPClientActivity.this.isFinishing()) {
String msg = br.readLine();
? ? ? ? ? ? ? ? System.out.println("receive:" + msg);
? ? ? ? ? ? ? ? if (msg !=null) {
String time = formatDateTime(System.currentTimeMillis());
? ? ? ? ? ? ? ? ? ? final String showedMsg ="server " + time +":" + msg +"\n";
? ? ? ? ? ? ? ? ? ? mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showedMsg).sendToTarget();
? ? ? ? ? ? ? ? }
}
System.out.println("quit...");
? ? ? ? ? ? mPrintWriter.close();
? ? ? ? ? ? br.close();
? ? ? ? ? ? socket.close();
? ? ? ? }catch (IOException e) {
e.printStackTrace();
? ? ? ? }
}
}
/** * 服務端代碼 */
public class TCPServerServiceextends Service {
private boolean mIsServiceDestoryed =false;
? ? private String[]mDefinedMessages =new String[]{
"你好啊,哈哈",
? ? ? ? ? ? "請問你叫什么名字",
? ? ? ? ? ? "今天深圳天氣很好呀,shy",
? ? ? ? ? ? "你知道嗎?我可是可以和多個人聊天的哦",
? ? ? ? ? ? "給你講個笑話吧:據(jù)說愛笑的人運氣不會太差,不知道真假。"
? ? };
? ? @Override
? ? public void onCreate() {
new Thread(new TcpServer()).start();
? ? ? ? super.onCreate();
? ? }
@Nullable
@Override
? ? public IBinderonBind(Intent intent) {
return null;
? ? }
@Override
? ? public void onDestroy() {
mIsServiceDestoryed =true;
? ? ? ? super.onDestroy();
? ? }
private class TcpServerimplements Runnable {
@Override
? ? ? ? public void run() {
ServerSocket serverSocket =null;
? ? ? ? ? ? try {
serverSocket =new ServerSocket(8688);
? ? ? ? ? ? }catch (IOException e) {
System.err.println("establish tcp server failed,port:8688");
? ? ? ? ? ? ? ? e.printStackTrace();
return;
? ? ? ? ? ? }
while (!mIsServiceDestoryed) {
//接受客戶頓請求
? ? ? ? ? ? ? ? try {
final Socket client = serverSocket.accept();
? ? ? ? ? ? ? ? ? ? System.out.println("accept");
? ? ? ? ? ? ? ? ? ? new Thread() {
@Override
? ? ? ? ? ? ? ? ? ? ? ? public void run() {
try {
responseClient(client);
? ? ? ? ? ? ? ? ? ? ? ? ? ? }catch (IOException e) {
e.printStackTrace();
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
}
}.start();
? ? ? ? ? ? ? ? }catch (IOException e) {
e.printStackTrace();
? ? ? ? ? ? ? ? }
}
}
}
private void responseClient(Socket client)throws IOException {
//用于接受客戶端消息
? ? ? ? BufferedReader in =new BufferedReader(new InputStreamReader(client.getInputStream()));
? ? ? ? //用于向客戶端發(fā)送消息
? ? ? ? PrintWriter out =new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
? ? ? ? out.println("歡迎來到聊天室!");
? ? ? ? while (!mIsServiceDestoryed) {
String str = in.readLine();
? ? ? ? ? ? System.out.println("msg from client:" + str);
? ? ? ? ? ? if (str ==null) {
//客戶端斷開連接
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
int i =new Random().nextInt(mDefinedMessages.length);
? ? ? ? ? ? String msg =mDefinedMessages[i];
? ? ? ? ? ? out.println(msg);
? ? ? ? ? ? System.out.println("send:" + msg);
? ? ? ? }
System.out.println("client quit.");
? ? ? ? //關閉流
? ? ? ? in.close();
? ? ? ? out.close();
? ? ? ? client.close();
? ? }
}