一、概述
网络通信无论在手机还是其他设备上都应用得非常广泛,因此掌握网络编程是非常有必要的,而我觉得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>
到这里,客户端和服务器的程序都写好了,在模拟器上运行客户端程序:
在真机上运行服务器程序:
接着,点击客户端“连接”按钮,输入一些内容再点击“发送”按钮:
此时服务器端的情况如下:
可见成功接收了客户端发送过来的数据。