您的位置:首页 > 移动开发 > Android开发

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源码:

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>


成果图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android Studio