基于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     <TextView
13         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     <LinearLayout
20         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         <EditText
27             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         <Button
33             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     <LinearLayout
41         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         <TextView
48             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         @Override
106         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         @Override
126         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         @Override
156         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) context
185                 .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。一样的代码,不一样的结果,很是不解,欢迎指教!

六.实际运行效果

时间: 2024-11-03 11:21:12

基于TCP的安卓服务器开发的相关文章

基于TCP协议的服务器中转简易聊天

项目比较简单:主要使用了TCP传输协议.多线程和swing窗口,以及IO流读写. 功能:各窗口之间简单的收发信息,另外附加一个抖动的效果. 服务器代码: 1 package com.java; 2 3 import java.awt.Dimension; 4 import java.awt.Toolkit; 5 import java.awt.event.ActionEvent; 6 import java.awt.event.ActionListener; 7 import java.awt.

基于Netbeans的安卓Android开发环境配置

基于Netbeans的安卓Android开发环境配置 一.准备工作 NetBeans 勾选网页中的Accept-选择对应系统下载安装即可,我电脑是XP32位,下载了windows X86,具体安装步骤可以百度,比较简单. Android SDK试用过,好使. 二.具体步骤 Netbeans->工具->插件->设置->添加->名称:NBAndroid URL:根据版本填写. URL填写: **Netbeans版本7.3 - 8.0填写: http://nbandroid.org

基于蓝牙的安卓客户端开发

一.安卓蓝牙开发基本流程 获取本地蓝牙适配器,打开蓝牙,获得已配对蓝牙设备列表 mBtAdapter = BluetoothAdapter.getDefaultAdapter(); mBtAdapter.enable(); Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices(); 扫描未配对设备,通过广播(BluetoothDevice.ACTION_FOUND)接收列表出未配对的设备 mBtAdapter.star

基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件[转]

上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfire插件.一步步很详细的介绍到简单插件开发,带Servlet的插件的开发.带JSP页面插件的开发,以及怎么样将开发好的插件打包.部署到openfire服务器. 如果你没有看上一篇文章的话,请你还是看看.http://www.cnblogs.com/hoojo/archive/2013/03/07/2947502.html 因为这篇文章是基于上篇文章讲叙的基础上完成插件开发.而且

一个基于TCP/IP的服务器与客户端通讯的小项目(超详细版)

1.目的:实现客户端向服务器发送数据 原理: 2.建立两个控制台应用,一个为服务器,用于接收数据.一个为客户端,用于发送数据. 关键类与对应方法: 1)类IPEndPoint: 1.是抽象类EndPoint的实现类 2.Socket对象的RemoteEndPoint. LocalEndPoint都是这个类型 3.属性Address: 使用IPv4表示的地址 4.属性Port:使用int表示的端口 2)类Socket: 这个类即可以用于作服务器端的开发,又可以作客户端的开发 构造方法: 参数 Ad

用c++开发基于tcp协议的文件上传功能

用c++开发基于tcp协议的文件上传功能 2005我正在一家游戏公司做程序员,当时一直在看<Windows网络编程> 这本书,把里面提到的每种IO模型都试了一次,强烈推荐学习网络编程的同学阅读,比 APUE 讲的更深入 这是某个银行广告项目(p2p传输视频)的一部分 IO模型采用的阻塞模式,文件一打开就直接上传 用vc 2003编译,生成win32 dll 麻雀虽小五脏俱全,CSimpleSocket,CReadStream dll 输出一虚类 extern "C" __d

linux网络编程 基于TCP的程序开发

面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你会觉得这样子的开发毫无激情.为什么TCP的开发就要按照这样的流程来呢?而且一般出的问题几乎都不在这几个系统调用上,原因何在?当我们弄清网络开发的本质,协议栈的设计原理.数据流向等这些问题的答案也就会慢慢浮出水面了.接下来这几篇博文主要是围绕网络编程展开,目的是引出后面对于Linux下TCP/IP协议

Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API,包括"套接字的地址结构"."字节排序函数"等.这些API几乎是所有的网络编程中都会使用的一些,对于我们正确的编写网络程序有很大的作用.在本节中我们会介绍编写一个基于TCP的套接字程序需要的一些API,同时会介绍一个完整的TCP客户服务器程序,虽然这个程序功能相对简单,但确包含了一个客户服务器程序所有的步骤,一些复杂的程序也都是在此基础上进行扩充.在后面随着学习的深入,我们会给这个程序添加功能. 下面

基于TCP网络通信的自动升级程序源码分析-客户端请求服务器上的升级信息

每次升级,客户端都会获取服务器端存放在upgradefile文件夹下的需要升级的文件和升级信息配置文件(即upgradeconfig.xml文件) 我们来看一下代码 //升级信息配置文件相对应的类 ( 升级信息配置文件是由这个类转化成的) private UpgradeConfig upgradeConfig = null; //客户端存储升级配置文件的地址 是放在客户端根目录下的 (就是把服务器 upgradefile/upgradeconfig.xml下载到客户端存放的位置) string