基于TCP的安卓服务器开发

一.说明

前文介绍了基于安卓客户端的开发,在此基础上,进行少许改动即可开发出一款基于TCP的安卓服务器,理论知识请参见笔者上一篇博文,下面直接实践操作。

二.权限申明

 1 <!--允许应用程序改变网络状态--> 2 <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> 3  4 <!--允许应用程序改变WIFI连接状态--> 5 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> 6  7  8 <!--允许应用程序访问有关的网络信息--> 9 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>10 11 <!--允许应用程序访问WIFI网卡的网络信息-->12 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>13 14 <!--允许应用程序完全使用网络-->15 <uses-permission android:name="android.permission.INTERNET"/>

三.布局文件

 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 <LinearLayout 6 android:layout_width="match_parent" 7 android:layout_height="wrap_content" 8 android:layout_marginLeft="10dp" 9 android:layout_marginRight="10dp"10 android:layout_marginTop="10dp"11 android:layout_marginBottom="10dp">12 <TextView13 android:id="@+id/LocalIPTextView"14 android:layout_width="match_parent"15 android:layout_height="wrap_content"16 android:hint="本机IP:"17 android:textSize="25dp"/>18 </LinearLayout>19 <LinearLayout20 android:layout_width="match_parent"21 android:layout_height="wrap_content"22 android:layout_marginLeft="10dp"23 android:layout_marginRight="10dp"24 android:layout_marginBottom="10dp">25 >26 <EditText27 android:id="@+id/MessagetoSendEditText"28 android:layout_width="0dp"29 android:layout_height="match_parent"30 android:layout_weight="3"31 android:text="Data from Server"/>32 <Button33 android:id="@+id/SendButton"34 android:layout_width="0dp"35 android:layout_height="wrap_content"36 android:layout_weight="1"37 android:text="发送"/>38 </LinearLayout>39 40 <LinearLayout41 android:layout_width="match_parent"42 android:layout_height="wrap_content"43 android:layout_marginLeft="10dp"44 android:layout_marginRight="10dp"45 46 android:layout_marginBottom="10dp">47 <TextView48 android:id="@+id/DisplayTextView"49 android:layout_width="match_parent"50 android:layout_height="wrap_content"51 android:textSize="25dp"/>52 </LinearLayout>53 54 55 </LinearLayout>

 

四.具体实现代码

 1 package com.example.john.androidsockettest; 2  3 import android.content.Context; 4 import android.net.ConnectivityManager; 5 import android.net.NetworkInfo; 6 import android.net.wifi.WifiInfo; 7 import android.net.wifi.WifiManager; 8 import android.os.Handler; 9 import android.os.Message; 10 import android.support.v7.app.AppCompatActivity; 11 import android.os.Bundle; 12 import android.view.View; 13 import android.widget.Button; 14 import android.widget.EditText; 15 import android.widget.TextView; 16  17 import java.io.BufferedReader; 18 import java.io.IOException; 19 import java.io.InputStreamReader; 20 import java.io.OutputStream; 21 import java.net.Inet4Address; 22 import java.net.InetAddress; 23 import java.net.NetworkInterface; 24 import java.net.ServerSocket; 25 import java.net.Socket; 26 import java.net.SocketException; 27 import java.util.Enumeration; 28  29 public class MainActivity extends AppCompatActivity { 30  31 //线程及套接字定义 32 public Socket socket = null; 33 public ServerSocket serverSocket = null; 34 private AcceptThread acceptThread = null; 35 private ReceiveThread receiveThread = null; 36 private SendThread sendThread = null; 37 //Handler中的消息类型 38 public static final int DEBUG = 0x00; 39 public static final int RECEIVEDATAFROMCLIENT = 0x01; 40 public static final int SENDDATATOCLIENT = 0x02; 41 //控件 42 private TextView localIPTextView; 43 private EditText messagetoSendEditText; 44 private Button sendButton; 45 private TextView displayTextView; 46 //变量定义 47 String messagetoSend=""; 48  49 public Handler myHandler = new Handler() { 50  @Override 51 public void handleMessage(Message msg) { 52 if (msg.what == RECEIVEDATAFROMCLIENT) { 53 Bundle bundle = msg.getData(); 54 displayTextView.append("Client:"+bundle.getString("string1")+"\n"); 55  } 56 else if (msg.what == DEBUG) { 57 Bundle bundle = msg.getData(); 58 displayTextView.append("Debug:"+bundle.getString("string1")+"\n"); 59  } 60 else if (msg.what == SENDDATATOCLIENT) { 61 Bundle bundle = msg.getData(); 62 displayTextView.append("Server:"+bundle.getString("string1")+"\n"); 63  } 64  } 65  66  }; 67 //子线程更新UI 68 public void SendMessagetoHandler(final int messageType , String string1toHandler){ 69 Message msg = new Message(); 70 msg.what = messageType; //消息类型 71 Bundle bundle = new Bundle(); 72  bundle.clear(); 73 bundle.putString("string1", string1toHandler); //向bundle中添加字符串 74  msg.setData(bundle); 75  myHandler.sendMessage(msg); 76  } 77  @Override 78 protected void onCreate(Bundle savedInstanceState) { 79 super.onCreate(savedInstanceState); 80  setContentView(R.layout.activity_main); 81 //控件对象获取 82 localIPTextView = (TextView)findViewById(R.id.LocalIPTextView); 83 messagetoSendEditText = (EditText)findViewById(R.id.MessagetoSendEditText); 84 sendButton = (Button)findViewById(R.id.SendButton); 85 displayTextView = (TextView)findViewById(R.id.DisplayTextView); 86 //服务器IP获取显示 87 localIPTextView.setText("本机IP:"+getIPAddress(this)); 88 //开启接受线程 89 acceptThread = new AcceptThread(); 90  acceptThread.start(); 91 sendButton.setOnClickListener(new View.OnClickListener() { 92  93  @Override 94 public void onClick(View v) { 95 messagetoSend = messagetoSendEditText.getText().toString(); 96 //使用连接成功后得到的socket构造发送线程,每点击一次send按钮触发一次发送线程 97 sendThread = new SendThread(socket); 98  sendThread.start(); 99  }100  });101 102  }103 //***** 接受线程 *****104 class AcceptThread extends Thread{105  @Override106 public void run() {107 try{108 serverSocket = new ServerSocket(8086);109 socket = serverSocket.accept();110 }catch (IOException e){111  e.printStackTrace();112  }113 SendMessagetoHandler(DEBUG,"客户端连接成功!");114 //构造并开启接收线程115 receiveThread = new ReceiveThread(socket);116  receiveThread.start();117  }118  }119 //******** 接收线程 **********120 class ReceiveThread extends Thread{121 122 private Socket mSocket;123 //接收线程的构造函数,由接受线程传入套接字124 public ReceiveThread(Socket socket){mSocket = socket;}125  @Override126 public void run() {127 while(true){ //连接成功后将一直运行128 try {129  BufferedReader bufferedReader;130 String line = null;131 String readBuffer="";132 bufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));133 134 while ((line = bufferedReader.readLine()) != null) {135 readBuffer = line + readBuffer;136  SendMessagetoHandler(RECEIVEDATAFROMCLIENT,readBuffer);137 readBuffer = "";138  }139 140 }catch (IOException e) {141  e.printStackTrace();142 //更新UI:显示发送错误信息143 SendMessagetoHandler(DEBUG,"接收失败!");144 return;145  }146  }147  }148  }149 //******** 发送线程 **********150 class SendThread extends Thread{151 private Socket mSocket;152 //发送线程的构造函数,由接受线程传入套接字153 public SendThread(Socket socket) {mSocket = socket;}154 155  @Override156 public void run() {157 try{158 OutputStream outputStream = mSocket.getOutputStream();159 //向服务器发送信息160 outputStream.write(messagetoSend.getBytes("gbk"));161  outputStream.flush();162 //更新UI:显示发送出的数据163  SendMessagetoHandler(SENDDATATOCLIENT,messagetoSend);164 }catch (IOException e) {165  e.printStackTrace();166 //更新UI:显示发送错误信息167 SendMessagetoHandler(DEBUG,"发送失败!");168 return;169  }170  }171  }172 //***** 获取本机的ip地址173 private String getlocalip(){174 WifiManager wifiManager = (WifiManager)this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);175 WifiInfo wifiInfo = wifiManager.getConnectionInfo();176 int ipAddress = wifiInfo.getIpAddress();177 // Log.d(Tag, "int ip "+ipAddress);178 if(ipAddress==0)return null;179 return ((ipAddress & 0xff)+"."+(ipAddress>>8 & 0xff)+"."180 +(ipAddress>>16 & 0xff)+"."+(ipAddress>>24 & 0xff));181  }182 183 public static String getIPAddress(Context context) {184 NetworkInfo info = ((ConnectivityManager) context185  .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();186 if (info != null && info.isConnected()) {187 if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络188 try {189 //Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces();190 for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {191 NetworkInterface intf = en.nextElement();192 for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {193 InetAddress inetAddress = enumIpAddr.nextElement();194 if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {195 return inetAddress.getHostAddress();196  }197  }198  }199 } catch (SocketException e) {200  e.printStackTrace();201  }202 203 } else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络204 WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);205 WifiInfo wifiInfo = wifiManager.getConnectionInfo();206 int ipAddress = wifiInfo.getIpAddress();//得到IPV4地址207 return ((ipAddress & 0xff)+"."+(ipAddress>>8 & 0xff)+"." //将得到的int类型的IP转换为String类型208 +(ipAddress>>16 & 0xff)+"."+(ipAddress>>24 & 0xff));209  }210 } else {211 //当前无网络连接,请在设置中打开网络212  }213 return null;214  }215 } 

 

 

五.Debug

  • readLine()

  在实际调试当中,还是遇到了上一篇博文中readLine问题,仍将代码贴下:

1 while ((line = bufferedReader.readLine()) != null) {2 readBuffer = line + readBuffer;3  SendMessagetoHandler(RECEIVEDATAFROMCLIENT,readBuffer);4 readBuffer = "";5 }

 

  这段读取输入流的代码与上篇博文是一样的,但调试的结果却有不同。上一篇中,服务器向客户端发送数据,即使没有带回车换行符,UI也会更新显示;然而这一篇中,客户端向服务器发送数据,如果数据结束不带上回车换行符的话,UI就不会更新显示,直到将客户端端口关闭,这时之前发送的数据会一下显示到UI。一样的代码,不一样的结果,很是不解,欢迎指教!

六.实际运行效果

 技术分享

相关文章