Android客户端与PC服务端、android服务端通过WiFi通信
前期准备:我的是Linux Mint操作系统(总之折腾的过程中怀疑过是不是系统的问题),首先是要创建wifi热点给android手机使用,这个时候笔记本作为通信的服务器端,android手机作为客户端,通过socket进行通信。
1.在eclipse下写好服务器端的代码,包括监听的端口好,客户端的IP地址获取,发送的数据处理等,这里涉及到J2EE的环境配置,有时间我在写下,这个代码是直接百度到的,能用:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class Test { private ServerSocket server; private Socket client; private BufferedReader in; private PrintWriter out; public Test() { try { server = new ServerSocket(9400); while (true) { System.out.println("start!"); // 获得客户端连接 client = server.accept(); // 获得客户端的IP和端口 String remoteIP = client.getInetAddress().getHostAddress(); int remotePort = client.getLocalPort(); System.out.println("A client connected. IP:" + remoteIP + ", Port: " + remotePort); System.out.println(); // 获得 client 端的输入输出流,为进行交互做准备 in = new BufferedReader(new InputStreamReader( client.getInputStream())); out = new PrintWriter(client.getOutputStream(), false); // 获得 client 端发送的数据 String tmp = in.readLine(); // String content = new String(tmp.getBytes("utf-8")); System.out.println("Client message is: " + tmp); // 向 client 端发送响应数据 out.println("Your message has been received successfully!."); // 关闭各个流 out.close(); in.close(); // server.close(); } } catch (Exception e) { // 发送响应,接收失败 System.out.println(e.toString()); out.println("Receive Error!"); } } public static void main(String[] args) { new Test(); } }
代码看起来也不是太难,关键是Java EE的使用,尤其是服务器的配置,(配置教程涉及到tomcat的配置,以及服务器的建立),
Project name随便写好了,然后next---->next,需要把Generate web.xml deployment descriptor勾选上。注意:
Java Resources 下的src文件夹下里面放的是相关的类,这个类写完之后还在Webcontent文件夹--->WEB-INF文件夹下的web.xml里面配置:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>TomcatTest</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>Test</servlet-name> <servlet-class>Test</servlet-class> </servlet> <servlet-mapping> <servlet-name>Test</servlet-name> <url-pattern></url-pattern> </servlet-mapping> </web-app>
到这里你可以运行你的服务端,选中项目,右击选中Run as--->Run on server,到此你的网站基本上就发布成功了,在你的手机的浏览器中输入你PC端的IP地址,注意端口号是9400,比如我之前测试的用是的10.3.19.26:9400,就可以看到服务端返回的信息。
2.android端的程序比较简单,但是一开始的时候怎么都不能成功运行,最后发现的两个问题a.权限没有加,b.自从android3.0以后,android的运行机制不容许在主线程中使用网络的相关操作
我的值加了这几个权限,貌似也能够运行起来,呵呵:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
第二个问题,网上的一些代码太坑了,明明都是有问题,也不知道修改,下面写的很简单,没有图形界面,
package com.example.client; import java.io.IOException; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; 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 { private Button btnConnect, btnSend; private Socket socket; private PrintStream output; private EditText editSend; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnConnect = (Button) findViewById(R.id.button1); btnSend = (Button) findViewById(R.id.button2); editSend = (EditText) findViewById(R.id.editText1); btnConnect.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub new Thread(runnable).start();//开启线程 } }); btnSend.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub sendMessage(editSend.getText().toString()); } }); } Runnable runnable = new Runnable() { @Override public void run() { // TODO Auto-generated method stub initClientSocket(); } }; public void initClientSocket() { try { EditText edit_ip = (EditText) MainActivity.this.findViewById(R.id.editText2); String ip = edit_ip.getText().toString().trim(); socket = new Socket("10.3.19.26", 9400); output = new PrintStream(socket.getOutputStream(), true, "gbk"); } catch (UnknownHostException e) { // TODO Auto-generated catch block Toast.makeText(MainActivity.this, "请检查端口号是否为服务器IP", Toast.LENGTH_LONG).show(); e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block Toast.makeText(MainActivity.this, "服务器未开启", Toast.LENGTH_LONG) .show(); e.printStackTrace(); } output.println("this is the message from client"); } private void sendMessage(String str) { output.println(str); } public void closeSocket() { try { output.close(); socket.close(); } catch (IOException e) { System.out.println("error"+e); } } }
基本上控件只有一个按钮,其他的都是没有用的,在按钮的监听器里面写的方法,就是使用Runable开启一个线程,在runable的方法中调用initClientSocket()方法,你会发现,里连接的代码很简单,我连接成功后就使用
output.println("this is the message from client");
这个就是返回给服务器的信息,一开始放在另一个按钮中的,但是考虑到上述的问题,还是直接在线程中发送(我测试过,在UI线程中不能使用这个方法,发送完了也没有反应)最终的服务器端接受的数据情况如下:
从下午到晚上总算弄完了2015-05-18 22:11:21,有时间把相关的配置弄下。
2015年5月19日星期二 21:53在github上看到一个程序,用的是内部异步任务方法处理的,放在这里参考下,很简单就是一个MainActivity.java:
1 package com.example.androidclient; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.net.Socket; 7 import java.net.UnknownHostException; 8 9 import android.os.AsyncTask; 10 import android.os.Bundle; 11 import android.app.Activity; 12 import android.view.View; 13 import android.view.View.OnClickListener; 14 import android.widget.Button; 15 import android.widget.EditText; 16 import android.widget.TextView; 17 18 public class MainActivity extends Activity { 19 20 TextView textResponse; 21 EditText editTextAddress, editTextPort;//用户自己输入的服务器端的地址和端口号 22 Button buttonConnect, buttonClear; 23 24 @Override 25 protected void onCreate(Bundle savedInstanceState) { 26 super.onCreate(savedInstanceState); 27 setContentView(R.layout.activity_main); 28 29 editTextAddress = (EditText)findViewById(R.id.address); 30 editTextPort = (EditText)findViewById(R.id.port); 31 buttonConnect = (Button)findViewById(R.id.connect); 32 buttonClear = (Button)findViewById(R.id.clear); 33 textResponse = (TextView)findViewById(R.id.response); 34 35 buttonConnect.setOnClickListener(buttonConnectOnClickListener); 36 37 buttonClear.setOnClickListener(new OnClickListener(){ 38 39 @Override 40 public void onClick(View v) { 41 textResponse.setText(""); 42 }}); 43 } 44 45 OnClickListener buttonConnectOnClickListener = 46 new OnClickListener(){//连接的监听器 47 48 @Override 49 public void onClick(View arg0) { 50 MyClientTask myClientTask = new MyClientTask( 51 editTextAddress.getText().toString(), 52 Integer.parseInt(editTextPort.getText().toString()));//构造异步任务内部类 53 myClientTask.execute(); 54 }}; 55 56 public class MyClientTask extends AsyncTask<Void, Void, Void> {//异步任务 57 58 String dstAddress; 59 int dstPort; 60 String response = ""; 61 62 MyClientTask(String addr, int port){//构造方法,传进IP地址和对应的端口号 63 dstAddress = addr; 64 dstPort = port; 65 } 66 67 @Override 68 protected Void doInBackground(Void... arg0) { 69 70 Socket socket = null;// 71 72 try { 73 socket = new Socket(dstAddress, dstPort);//建立连接,需要try-catch 74 75 ByteArrayOutputStream byteArrayOutputStream = 76 new ByteArrayOutputStream(1024); 77 byte[] buffer = new byte[1024]; 78 79 int bytesRead; 80 InputStream inputStream = socket.getInputStream(); 81 82 /* 83 * notice: 84 * inputStream.read() will block if no data return 85 */ 86 while ((bytesRead = inputStream.read(buffer)) != -1){ 87 byteArrayOutputStream.write(buffer, 0, bytesRead); 88 response += byteArrayOutputStream.toString("UTF-8"); 89 } 90 91 } catch (UnknownHostException e) { 92 // TODO Auto-generated catch block 93 e.printStackTrace(); 94 response = "UnknownHostException: " + e.toString(); 95 } catch (IOException e) { 96 // TODO Auto-generated catch block 97 e.printStackTrace(); 98 response = "IOException: " + e.toString(); 99 }finally{ 100 if(socket != null){ 101 try { 102 socket.close(); 103 } catch (IOException e) { 104 // TODO Auto-generated catch block 105 e.printStackTrace(); 106 } 107 } 108 } 109 return null; 110 } 111 112 @Override 113 protected void onPostExecute(Void result) {//更新UI线程 114 textResponse.setText(response); 115 super.onPostExecute(result); 116 } 117 118 } 119 120 }
那么对应的服务器android端的代码如下,写的也很简单浅显易懂:MainActivity.java
package com.example.androidserversocket; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.Enumeration; import android.os.Bundle; import android.app.Activity; import android.widget.TextView; public class MainActivity extends Activity { TextView info, infoip, msg; String message = ""; ServerSocket serverSocket;//ServerSocket实例 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); info = (TextView) findViewById(R.id.info); infoip = (TextView) findViewById(R.id.infoip); msg = (TextView) findViewById(R.id.msg); infoip.setText(getIpAddress());// Thread socketServerThread = new Thread(new SocketServerThread()); socketServerThread.start(); } @Override protected void onDestroy() { super.onDestroy(); if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private class SocketServerThread extends Thread { static final int SocketServerPORT = 8080; int count = 0; @Override public void run() { try { serverSocket = new ServerSocket(SocketServerPORT);//监听端口 MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { info.setText("I'm waiting here: " + serverSocket.getLocalPort()); } }); while (true) {//接受客户端的信息 Socket socket = serverSocket.accept(); count++; message += "#" + count + " from " + socket.getInetAddress() + ":" + socket.getPort() + "\n"; MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { msg.setText(message); } }); SocketServerReplyThread socketServerReplyThread = new SocketServerReplyThread( socket, count); socketServerReplyThread.run(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private class SocketServerReplyThread extends Thread { private Socket hostThreadSocket; int cnt; SocketServerReplyThread(Socket socket, int c) { hostThreadSocket = socket; cnt = c; } @Override public void run() { OutputStream outputStream; String msgReply = "Hello from Android, you are #" + cnt; try { outputStream = hostThreadSocket.getOutputStream(); PrintStream printStream = new PrintStream(outputStream); printStream.print(msgReply); printStream.close(); message += "replayed: " + msgReply + "\n"; MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { msg.setText(message); } }); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); message += "Something wrong! " + e.toString() + "\n"; } MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { msg.setText(message); } }); } } private String getIpAddress() { String ip = ""; try { Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface .getNetworkInterfaces(); while (enumNetworkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = enumNetworkInterfaces .nextElement(); Enumeration<InetAddress> enumInetAddress = networkInterface .getInetAddresses(); while (enumInetAddress.hasMoreElements()) { InetAddress inetAddress = enumInetAddress.nextElement(); if (inetAddress.isSiteLocalAddress()) { ip += "SiteLocalAddress: " + inetAddress.getHostAddress() + "\n"; } } } } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); ip += "Something Wrong! " + e.toString() + "\n"; } return ip; } }