android socket通信(上)

来源:互联网 发布:淘宝店铺冻结能退货吗 编辑:程序博客网 时间:2024/06/05 09:41




今天我们介绍android下的socket通信,并编写一个小程序:android作为客户端,通过socket发送数据到我们的pc机,pc机就是服务器。


分两个实验完成:我们先在模拟器上实现,然后在真实的手机上实现。



1.
设置环境,两个实验均在ubuntu11.04下完成:
第一个实验是android模拟器作为客户端,第二个实验是真实的android手机作为客户端,两个实验的服务器都是我们的pc机,并且服务器端用c++实现,客户端用java实现:
第一个实验的ip配置:
主机eth0:192.168.1.2
pc服务器端口:9400



第二个实验的ip配置:
主机lwan0:192.168.1.100
pc服务器端口:9500




注意,第一个实验是android模拟器作为客户端,因此要设置主机的eth0的ip地址,而第二个实验是真实的android手机作为客户端,它和pc机(服务器)在一个无线路由器局域网里,因此我们要设置主机的lwan的ip地址,不过由于主机和真实手机的ip都是路由器dhcp自动分配的,因此无需额外的配置命令,你可以改成你自己的ip地址。


第一个实验的配置命令很简单:
sudo ifconfig eth0 192.168.1.2




首先介绍第一个实验:

由于模拟器的特殊性,因此我们需要将模拟器的端口映射到主机的某个端口,这样才可以和模拟器相互通信。



1.
端口映射:
在android sdk的platform-tools下有一个adb可执行程序,我的路径是android-sdk-linux_x86/platform-tools/adb,运行如下命令进行端口映射:

cd android-sdk-linux_x86/platform-tools

./adb forward tcp:9400 tcp:9400



上面命令的意思是将模拟器的9400端口映射到主机的9400端口,这样模拟器向192.168.1.2:9400发送的数据就会被映射到主机的9400端口(主机的ip地址是192.168.1.2),而我们的主机只要监听本地的9400端口即可。这里我们使用tcp socket




2.
环境配置完毕并了解了基本原理后,直接上代码,下面是客户端的代码,用java实现:
src/BogoclientActivity.java
[java] view plaincopy
  1. package bogo.client.com;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintStream;  
  5. import java.net.Socket;  
  6. import java.net.UnknownHostException;  
  7.   
  8. import android.app.Activity;  
  9. import android.os.Bundle;  
  10. import android.view.View;  
  11. import android.widget.Button;  
  12. import android.widget.EditText;  
  13. import android.widget.Toast;  
  14.   
  15.   
  16. public class BogoclientActivity extends Activity  
  17. {  
  18.   /* 服务器地址 */  
  19.   private final String SERVER_HOST_IP = "192.168.1.2";  
  20.   
  21.   /* 服务器端口 */  
  22.   private final int SERVER_HOST_PORT = 9400;  
  23.     
  24.   private Button btnConnect;  
  25.   private Button btnSend;  
  26.   private EditText editSend;  
  27.   private Socket socket;  
  28.   private PrintStream output;  
  29.   
  30.   
  31.   public void toastText(String message)  
  32.   {  
  33.     Toast.makeText(this, message, Toast.LENGTH_LONG).show();  
  34.   }  
  35.   
  36.   public void handleException(Exception e, String prefix)  
  37.   {  
  38.     e.printStackTrace();  
  39.     toastText(prefix + e.toString());  
  40.   }  
  41.   
  42.   /** Called when the activity is first created. */  
  43.   @Override  
  44.   public void onCreate(Bundle savedInstanceState)  
  45.   {  
  46.     super.onCreate(savedInstanceState);  
  47.     setContentView(R.layout.main);  
  48.   
  49.     initView();  
  50.   
  51.     btnConnect.setOnClickListener(new Button.OnClickListener()  
  52.     {  
  53.       @Override  
  54.       public void onClick(View v)  
  55.       {  
  56.         initClientSocket();  
  57.       }  
  58.     });  
  59.       
  60.     btnSend.setOnClickListener(new Button.OnClickListener()  
  61.     {  
  62.       @Override  
  63.       public void onClick(View v)  
  64.       {  
  65.         sendMessage(editSend.getText().toString());  
  66.       }  
  67.     });  
  68.   }  
  69.     
  70.   public void initView()  
  71.   {  
  72.     btnConnect = (Button)findViewById(R.id.btnConnect);  
  73.     btnSend = (Button)findViewById(R.id.btnSend);  
  74.     editSend = (EditText)findViewById(R.id.sendMsg);  
  75.   
  76.     btnSend.setEnabled(false);  
  77.     editSend.setEnabled(false);  
  78.   }  
  79.   
  80.   public void closeSocket()  
  81.   {  
  82.     try  
  83.     {  
  84.       output.close();  
  85.       socket.close();  
  86.     }  
  87.     catch (IOException e)  
  88.     {  
  89.       handleException(e, "close exception: ");  
  90.     }  
  91.   }  
  92.     
  93.   private void initClientSocket()  
  94.   {  
  95.     try  
  96.     {  
  97.       /* 连接服务器 */  
  98.       socket = new Socket(SERVER_HOST_IP, SERVER_HOST_PORT);  
  99.   
  100.       /* 获取输出流 */  
  101.       output = new PrintStream(socket.getOutputStream(), true"utf-8");  
  102.         
  103.       btnConnect.setEnabled(false);  
  104.       editSend.setEnabled(true);  
  105.       btnSend.setEnabled(true);  
  106.     }  
  107.     catch (UnknownHostException e)  
  108.     {  
  109.       handleException(e, "unknown host exception: " + e.toString());  
  110.     }  
  111.     catch (IOException e)  
  112.     {  
  113.       handleException(e, "io exception: " + e.toString());  
  114.     }  
  115.   }  
  116.     
  117.   private void sendMessage(String msg)  
  118.   {  
  119.     output.print(msg);  
  120.   }  
  121. }  


layout/main.xml

[plain] view plaincopy
  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:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="@string/hello" />  
  11.   
  12.     <Button  
  13.         android:id="@+id/btnConnect"  
  14.         android:layout_width="fill_parent"  
  15.         android:layout_height="wrap_content"  
  16.         android:text="@string/connect" />  
  17.   
  18.     <EditText  
  19.         android:id="@+id/sendMsg"  
  20.         android:layout_width="match_parent"  
  21.         android:layout_height="wrap_content"  
  22.         android:inputType="text" />  
  23.   
  24.     <Button  
  25.         android:id="@+id/btnSend"  
  26.         android:layout_width="fill_parent"  
  27.         android:layout_height="wrap_content"  
  28.         android:text="@string/send" />  
  29.   
  30. </LinearLayout>  



不要忘了,在AndroidManifest.xml中添加访问网络权限:
<uses-permission android:name="android.permission.INTERNET" />



把上面的代码编译并下载到模拟器中


3.
服务器端的代码,用c++实现:
server.c

[cpp] view plaincopy
  1. #include <sys/types.h>  
  2. #include <sys/socket.h>  
  3. #include <netinet/in.h>  
  4. #include <arpa/inet.h>  
  5. #include <unistd.h>  
  6. #include <stdlib.h>  
  7. #include <stdio.h>  
  8.   
  9. #define PORT 9400  
  10. #define MAX_BUFFER 1024  
  11.   
  12.   
  13. int main()  
  14. {  
  15.   /* create a socket */  
  16.   int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  17.     
  18.   struct sockaddr_in server_addr;  
  19.   server_addr.sin_family = AF_INET;  
  20.   server_addr.sin_addr.s_addr = inet_addr("192.168.1.2");  
  21.   server_addr.sin_port = htons(PORT);  
  22.     
  23.   /* bind with the local file */  
  24.   bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));  
  25.     
  26.   /* listen */  
  27.   listen(server_sockfd, 5);  
  28.     
  29.   int size;  
  30.   char buffer[MAX_BUFFER + 1];  
  31.   int client_sockfd;  
  32.   struct sockaddr_in client_addr;  
  33.   socklen_t len = sizeof(client_addr);  
  34.     
  35.   /* accept a connection */  
  36.   printf("waiting connection...\n");  
  37.   client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len);  
  38.   printf("connection established!\n");  
  39.       
  40.   while(1)  
  41.   {  
  42.     printf("waiting message...\n");  
  43.       
  44.     /* exchange data */  
  45.     size = read(client_sockfd, buffer, MAX_BUFFER);  
  46.     buffer[size] = '\0';  
  47.     printf("Got %d bytes: %s\n", size, buffer);  
  48.   }  
  49.   
  50.   /* close the socket */  
  51.   close(client_sockfd);  
  52.         
  53.   return 0;  
  54. }  

Makefile:

[plain] view plaincopy
  1. all: server.c  
  2.     gcc -g -Wall -o server server.c  
  3.   
  4. clean:  
  5.     rm -rf *.o server  



4.
运行结果:


首先运行服务器代码,然后运行模拟器的bogoclient程序,如下图,pc机正等待模拟器连接,并且未连接之前模拟器的文本对话框和send按钮都是不可用的:




点击connect按钮进行连接,连接成功后我们发现文本框和send按钮可用了,connect按钮不可用了,并且主机从等待连接状态变成了等待数据状态:





输入一些文本后按send按钮,pc机就会打印出模拟器发来的文本数据:



注意,如果模拟器连接时提示Connect refused,那么把模拟器的bogoclient和pc机上的server都结束掉,然后重新开始。



代码不过多解释了,注释挺详细的,有关pc机上的tcp通信,可以参考:

http://blog.csdn.net/htttw/article/details/7519964



最后,我把这个服务器和客户端两个程序都上传上来,供大家下载:

http://download.csdn.net/detail/htttw/4307606



在下一篇里,我们要把这个程序移植到真实的android手机上了:

http://blog.csdn.net/htttw/article/details/7574409

0 0