Android之发送接收服务器消息
2015-09-02 18:35
996 查看
一:什么是Socket
它实际上是网络通信的一种接口,基于不同的协议,有各种不同的Socket,比如有基于TCP协议的Socket和基于UDP协议的Socket以及基于蓝牙协议的Socket,Android中使用的是Java的Socket模型。
Socket在计算机行业通常称为”套接字“,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求。这是一个比较抽象的概念。计算机是拥有端口的,每一个端口都可以有一个应用程序来进行通讯的使用,比如:80端口是HTTP协议所使用的端口,21端口是FTP协议所使用的端口,端口是计算机和外界通讯的接口,这些接口都是逻辑的接口,端口号取值的范围是零到256乘以256减1,1024以下的端口都是操作系统使用的保留端口,以上的端口我们可以自由的来使用,不要和其他应用程序的端口冲突。
应用程序可以通过“套接字”向网络发送请求或者应答网络的请求,这时候就把Socket分成了两部分,一部分是服务器端的Socket,这个Socket主要用来接收来自网络的请求,它一直监听在某一个端口上。一部分是客户端的Socket,这个Socket主要用来向网络发送数据。
二:Socket通讯模型
-UDP协议和TCP协议
UDP协议和TCP协议是互联网使用最广的两种协议都是基于IP的协议。第一个区别是UDP协议是一个不太靠谱的协议,UDP协议把数据都打成数据包,数据包上自带通讯地址,也就是说我要把这个数据包发送到网络上的哪一个地址,通过网络把这个数据包发送出去,至于这个数据包是否发送到目的地,是否服务器端接收到了这个数据包,这个协议并不保证,就像中国的邮政,你是把信寄出去了,但是邮政系统不保证对方能收到你寄送的信。TCP发送数据的时候要求接收方接收到数据之后给一个回应,也就是你是否收到了,TCP可靠一些,当我们发送一些比较重要的数据的时候一般都使用TCP协议。另外一个区别是UDP协议发送的一个数据包它的容量是有限的,而TCP协议则没有这样一个限制。并不是说UDP协议一定就不如TCP协议,在不同的领域有不同是使用,UDP协议好处是速度相对快些。TCP协议相对慢些。
-Socket通讯流程
应用程序通过“套接字”也就是Socket可以选择这两种协议当中的一种,你可以选择用UDP发送数据,也可以选择用TCP发送数据,数据发送出去通过“通信信道”也就是IP的基础网络,来到服务器端(接收端),就可以接收到数据了。发送数据的时候用UDP协议,接收的时候也要用UDP协议,发送数据的时候用TCP协议,接收的时候也要用TCP协议,在发送的时候指定接收端的IP地址和端口号就可以了,究竟数据包或数据是如何发送的,框架已经帮我们封装好了,我们不去关心它了。
一个客户端要发起一次通信,首先必须知道运行服务器端的主机IP地址和通信端口。然后由网络基础设施利用目标地址,将客户端发送的信息传递到正确的主机上,在Java中,地址可以由字符串来定义,字符串可以使数字型的地址(比如172.16.21.202),也可以是主机名,端口为6610。下面实现一个例子,手机为客户端,PC机(Windows系统)为服务器,手机和服务器约定一个端口号6610。手机通过socket向服务器发送消息,服务器监听约定的端口号6610,接收来自客户端的socket套接字,同时客户端显示已发送的消息。服务器也可以给手机客户端发送消息,手机客户端收到消息并显示出来。从而实现从手机端与服务器互相通信。
本文主要基于TCP协议来进行数据的发送,通常用于发送文件采用这种方式。
TCP协议通讯模型
1:工作流程
首先有两部分客户端和服务器端,客户端需要Socket这个类的对象,而服务器端需要ServerSocket这个类的对象,由客户端Socket发送一个请求,服务器端的ServerSocket在计算机的某一个端口号上进行监听,监听客户端发送的请求之后,那么客户端和服务器端的一个通讯通道就建立起来了,这时候呢既可以从客户端向服务器端发送数据,服务器端也可以给客户端相应的响应。在客户端发送数据的时候我们需要用到IO流里面的OutputStream,通过这个OutputStream把数据发送给服务器端,服务器端用InputStream来读取客户端当中用OutputStream所写入的数据。生活举例:就像双方男女朋友打电话一样,男孩(客户端)说话(数据)通过听筒发送到电话网络中去,当男孩说话的时候就相当于咱们这里的通过OutputStream向互联网中写入数据,而作为接听的这个女孩(服务器端)那么男孩(客户端)说的内容就是女孩(服务器端)听到的内容,那么就是说服务器端可以通过InputStream把客户端当中通过OutputStream所写入的数据给它读取出来,反之亦然,如果服务器端想向客户端发送数据,那么就使用OutputStream写出数据,在客户端通过InputStream把服务器端当中通过OutputStream所写入的数据给它读取出来。就像打电话一样,你说的就是我听的,你听的就是我说的。
附上客户端代码,服务器端为Windows系统电脑,采用了NetAssist软件
Java源码:
Androidmanifest源码:
activity_main源码:
成果图:
它实际上是网络通信的一种接口,基于不同的协议,有各种不同的Socket,比如有基于TCP协议的Socket和基于UDP协议的Socket以及基于蓝牙协议的Socket,Android中使用的是Java的Socket模型。
Socket在计算机行业通常称为”套接字“,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求。这是一个比较抽象的概念。计算机是拥有端口的,每一个端口都可以有一个应用程序来进行通讯的使用,比如:80端口是HTTP协议所使用的端口,21端口是FTP协议所使用的端口,端口是计算机和外界通讯的接口,这些接口都是逻辑的接口,端口号取值的范围是零到256乘以256减1,1024以下的端口都是操作系统使用的保留端口,以上的端口我们可以自由的来使用,不要和其他应用程序的端口冲突。
应用程序可以通过“套接字”向网络发送请求或者应答网络的请求,这时候就把Socket分成了两部分,一部分是服务器端的Socket,这个Socket主要用来接收来自网络的请求,它一直监听在某一个端口上。一部分是客户端的Socket,这个Socket主要用来向网络发送数据。
二:Socket通讯模型
-UDP协议和TCP协议
UDP协议和TCP协议是互联网使用最广的两种协议都是基于IP的协议。第一个区别是UDP协议是一个不太靠谱的协议,UDP协议把数据都打成数据包,数据包上自带通讯地址,也就是说我要把这个数据包发送到网络上的哪一个地址,通过网络把这个数据包发送出去,至于这个数据包是否发送到目的地,是否服务器端接收到了这个数据包,这个协议并不保证,就像中国的邮政,你是把信寄出去了,但是邮政系统不保证对方能收到你寄送的信。TCP发送数据的时候要求接收方接收到数据之后给一个回应,也就是你是否收到了,TCP可靠一些,当我们发送一些比较重要的数据的时候一般都使用TCP协议。另外一个区别是UDP协议发送的一个数据包它的容量是有限的,而TCP协议则没有这样一个限制。并不是说UDP协议一定就不如TCP协议,在不同的领域有不同是使用,UDP协议好处是速度相对快些。TCP协议相对慢些。
-Socket通讯流程
应用程序通过“套接字”也就是Socket可以选择这两种协议当中的一种,你可以选择用UDP发送数据,也可以选择用TCP发送数据,数据发送出去通过“通信信道”也就是IP的基础网络,来到服务器端(接收端),就可以接收到数据了。发送数据的时候用UDP协议,接收的时候也要用UDP协议,发送数据的时候用TCP协议,接收的时候也要用TCP协议,在发送的时候指定接收端的IP地址和端口号就可以了,究竟数据包或数据是如何发送的,框架已经帮我们封装好了,我们不去关心它了。
一个客户端要发起一次通信,首先必须知道运行服务器端的主机IP地址和通信端口。然后由网络基础设施利用目标地址,将客户端发送的信息传递到正确的主机上,在Java中,地址可以由字符串来定义,字符串可以使数字型的地址(比如172.16.21.202),也可以是主机名,端口为6610。下面实现一个例子,手机为客户端,PC机(Windows系统)为服务器,手机和服务器约定一个端口号6610。手机通过socket向服务器发送消息,服务器监听约定的端口号6610,接收来自客户端的socket套接字,同时客户端显示已发送的消息。服务器也可以给手机客户端发送消息,手机客户端收到消息并显示出来。从而实现从手机端与服务器互相通信。
本文主要基于TCP协议来进行数据的发送,通常用于发送文件采用这种方式。
TCP协议通讯模型
1:工作流程
首先有两部分客户端和服务器端,客户端需要Socket这个类的对象,而服务器端需要ServerSocket这个类的对象,由客户端Socket发送一个请求,服务器端的ServerSocket在计算机的某一个端口号上进行监听,监听客户端发送的请求之后,那么客户端和服务器端的一个通讯通道就建立起来了,这时候呢既可以从客户端向服务器端发送数据,服务器端也可以给客户端相应的响应。在客户端发送数据的时候我们需要用到IO流里面的OutputStream,通过这个OutputStream把数据发送给服务器端,服务器端用InputStream来读取客户端当中用OutputStream所写入的数据。生活举例:就像双方男女朋友打电话一样,男孩(客户端)说话(数据)通过听筒发送到电话网络中去,当男孩说话的时候就相当于咱们这里的通过OutputStream向互联网中写入数据,而作为接听的这个女孩(服务器端)那么男孩(客户端)说的内容就是女孩(服务器端)听到的内容,那么就是说服务器端可以通过InputStream把客户端当中通过OutputStream所写入的数据给它读取出来,反之亦然,如果服务器端想向客户端发送数据,那么就使用OutputStream写出数据,在客户端通过InputStream把服务器端当中通过OutputStream所写入的数据给它读取出来。就像打电话一样,你说的就是我听的,你听的就是我说的。
附上客户端代码,服务器端为Windows系统电脑,采用了NetAssist软件
Java源码:
com.zhd.helloandroid.t; import android.app.Activity; import android.os.AsyncTask; import android.os.Handler; import android.os.Bundle; import android.os.Message; import android.view.Menu; import android.view.View; import android.widget.EditText; import android.widget.TextView; import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date; public class MainActivity extends Activity implements View.OnClickListener { private EditText mIPEdt, mPortEdt, mSocketIDEdt, mMessageEdt; private static TextView mConsoleTxt; private static StringBuffer mConsoleStr = new StringBuffer(); private Socket mSocket; private boolean isStartRecieveMsg; //private SocketHandler mHandler; protected BufferedReader mReader;//BufferedWriter 用于推送消息 protected BufferedWriter mWriter;//BufferedReader 用于接收消息 private String content = ""; //接收线程发送过来信息,并用TextView显示 public Handler mHandler = new Handler() { public void handleMessage(Message msg) { //super.handleMessage(msg); mConsoleStr.append("服务器:" + msg.obj.toString() + " " + getTime(System.currentTimeMillis()) + "\n"); mConsoleTxt.setText(mConsoleStr); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { mIPEdt = (EditText) findViewById(R.id.ip_edt); //mIPEdt.setText("172.16.21.202"); m 4000 PortEdt = (EditText) findViewById(R.id.port_edt); //mPortEdt.setText("6610"); mMessageEdt = (EditText) findViewById(R.id.msg_edt); mConsoleTxt = (TextView) findViewById(R.id.console_txt); findViewById(R.id.start_btn).setOnClickListener(this); findViewById(R.id.send_btn).setOnClickListener(this); findViewById(R.id.clear_btn).setOnClickListener(this); } /** * 初始化socket */ private void initSocket() { //新建一个线程,用于初始化socket和检测是否有接收到新的消息 Thread thread = new Thread(new Runnable() { @Override public void run() { String ip = mIPEdt.getText().toString();//IP int port = Integer.parseInt(mPortEdt.getText().toString());//Socket try { isStartRecieveMsg = true; mSocket = new Socket(ip, port); mReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream())); mWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream(), "utf-8")); //接收来自服务器的消息 while(isStartRecieveMsg) { if(mReader.ready()) { /*读取一行字符串,读取的内容来自于客户机 reader.readLine()方法是一个阻塞方法, 从调用这个方法开始,该线程会一直处于阻塞状态, 直到接收到新的消息,代码才会往下走*/ //String data = mReader.readLine(); String txt = ""; while ((content = mReader.readLine()) != null) { //txt = content ; mHandler.sendMessage(mHandler.obtainMessage(0, content)); } mReader.close(); //handler发送消息,在handleMessage()方法中接收 //mHandler.obtainMessage(0, data).sendToTarget(); } Thread.sleep(200); } mWriter.close(); mSocket.close(); } catch (Exception e) { e.printStackTrace(); } } }); thread.start(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.send_btn: send(); break; case R.id.clear_btn: mConsoleStr.delete(0, mConsoleStr.length()); mConsoleTxt.setText(mConsoleStr.toString()); break; case R.id.start_btn: if(!isStartRecieveMsg) { initSocket(); } break; default: break; } } /** * 发送 */ private void send() { new AsyncTask<String, Integer, String>() { @Override protected String doInBackground(String... params) { sendMsg(); return null; } }.execute(); } /** * 发送消息 */ protected void sendMsg() { try { //String socketID = mSocketIDEdt.getText().toString().trim(); String msg = mMessageEdt.getText().toString().trim(); JSONObject json = new JSONObject(); //json.put("to", socketID); json.put("msg", msg); mWriter.write(json.toString() + "\n"); mWriter.flush(); mConsoleStr.append("我:" + msg + " " + getTime(System.currentTimeMillis()) + "\n"); mConsoleTxt.setText(mConsoleStr); } catch (Exception e) { e.printStackTrace(); } } @Override public void onBackPressed() { super.onBackPressed(); isStartRecieveMsg = false; } private static String getTime(long millTime) { Date d = new Date(millTime); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(d); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } }
Androidmanifest源码:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.zhd.helloandroid.t" > <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
activity_main源码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical"> <EditText android:id="@+id/ip_edt" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:hint="服务器IP地址"/> <EditText android:id="@+id/port_edt" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="端口"/> <Button android:id="@+id/start_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="连接"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="horizontal"> <TextView android:id="@+id/console_txt" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent"/> <Button android:id="@+id/clear_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:text="清除"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical"> <EditText android:id="@+id/msg_edt" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:hint="请输入要发送的内容" android:gravity="top" /> <Button android:id="@+id/send_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="发送"/> </LinearLayout> </LinearLayout>
成果图:
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories