您的位置:首页 > 理论基础 > 计算机网络

Android网络编程实践之旅(二):基于Socket的网络通信

2014-11-29 12:58 741 查看
http://blog.csdn.net/harry_helei/article/details/6638876 好文章,再转一次。

Socket(套接字)是一种通信机制,可以实现单机或跨网络进行通信,其创建需要明确的区分C(客户端)/S(服务器端),支持多个客户端连接到同一个服务器。有两种传输模式:

1)、面向连接的传输:基于TCP协议,可靠性高,但效率低;

2)、面向无连接的传输:基于UDP协议,可靠性低,但效率高;

Android中,直接采用Socket通信应该是我们遇到的最低级的网络运用。尽管已经作了很大程度的抽象,但是纯粹的Socket通信,仍然给开发者留下很多细节需要处理,尤其在服务器端,开发者需要处理多线程以及数据缓冲等的设计问题。相对而言,处于更高抽象层的HTTP等,已经对Socket通信中需要处理的技术细节进行了很好的封装,开发者无须关心,因此,HTTP在网络开发中通常具有决定性的优势。

Android在其核心库的java包中,提供了用于客户端的Socket class和用于服务器端的ServerSocket class,分别位于$SOURCE/libcore/luni/src/main/java/java/net/Socket.java和$SOURCE/libcore/luni/src/main/java/java/net/ServerSocket.java文件中。分析两个class的源码,可以看出封装考虑的很全面,只构造方法一向每个class都考虑了很多种使用情况。由于本人只是初学者,很多理解的不深入,这里只抛砖引玉的对两个class的构造方法分别介绍一种,就是我下面的程序中用到的:

Socket(String dstName, int dstPort):创建一个以流的方式(基于TCP协议)连接到目标机(这里可以理解为服务器)的客户端Socket;dstName是目标机的IP地址,dstPort是要连接的目标机的端 口号。这里要注意对端口的理解,它不能理解为物理上的一个接口,而是对计算机中一块特殊内存区域的形象表述。

ServerSocket(int aport):创建一个绑定到本机指定端口的服务端Socket;aport就是指定的本机端口。与上述客户端Socket对应,通过TCP连接时,ServerSocket创建后需要在aport端口上进行监听,等待客户端的连接。

上面所写都是些背景知识,下面对本人的编程实践进行详细说明。

1、功能描述

1)、简单的基于Socket的数据通信;

2)、采用TCP方式连接;

3)、采用C/S结构,但服务端只支持一个连接;

4)、客户端能够向服务端发送数据,并显示服务端的返回信息;

5)、服务端能够接收客户端的数据,并将收到的数据以特定的方式返回给客户端;

2、程序实现思路

1)、服务端:设计为在后台执行的service,用一个独立的线程来处理客户端的连接请求、数据接收和返回。为了启动该service,编写个简单的Activity。

2)、客户端:设计为一个Activity,界面由三部分组成:显示服务端返回信息的文本区域(一个文本框);进行数据输入的编辑区域(一个编辑框);以及触发连接请求并执行数据发送的触发区域(一个按钮)。

3、服务端源程序

1)、Activity文件SocketServerDemo.java

[java]
view plaincopy

package com.android.sample.SocketServerDemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class SocketServerDemo extends Activity{

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

System.out.println("begin start service");
this.startService(new Intent(this, SocketService.class));
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();

this.stopService(new Intent(this, SocketService.class));
}
}

2)、service文件SocketService.java

[java]
view plaincopy

package com.android.sample.SocketServerDemo;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class SocketService extends Service{
Thread mServiceThread;

Socket client;

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();

mServiceThread = new Thread(new SocketServerThread());
}

@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);

mServiceThread.start();
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}

public class SocketServerThread extends Thread {
private static final int PORT = 54321;

private SocketServerThread(){
}

@Override
public void run() {
try {
ServerSocket server = new ServerSocket(PORT);

while(true){
System.out.println("begin client connected");
client = server.accept();
System.out.println("client connected");

BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println("read from client:");

String textLine = reader.readLine();
if(textLine.equalsIgnoreCase("EXIT")){
System.out.println("EXIT invoked, closing client");
break;
}

System.out.println(textLine);

PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())));

writer.println("ECHO from server: " + textLine);
writer.flush();

writer.close();
reader.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
System.err.println(e);
}
}

}
}

3)、AndroidManifest.xml文件,因为需要在其中添加service和网络访问权限,这里一并贴出

[html]
view plaincopy

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.sample.SocketServerDemo"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".ScreenCastServer"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service android:name="com.android.sample.SocketServerDemo.SocketService">
</service>

</application>

<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

4、客户端程序
1)、布局文件main.xml

[html]
view plaincopy

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/receive_msg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>

<EditText
android:id="@+id/edit_msg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>

<Button
android:id="@+id/send_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="send"
/>
</LinearLayout>

2)、Activity文件SocketClientDemo.java

[java]
view plaincopy

package com.android.sample.SocketClientDemo;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class SocketClientDemo extends Activity {
private static final String SERVERIP = "192.168.1.68";
private static final int SERVERPORT = 54321;

TextView mMsgRev;
EditText mMsgEdit;
Button mMsgSendBtn;

String mSendMsg;
String mReceivedMsg;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

mMsgRev = (TextView)findViewById(R.id.receive_msg);
mMsgEdit = (EditText)findViewById(R.id.edit_msg);
mMsgSendBtn = (Button)findViewById(R.id.send_msg);

mMsgSendBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Socket socket = null;
mSendMsg = mMsgEdit.getText().toString();

try {
socket = new Socket(SERVERIP, SERVERPORT);

PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
writer.println(mSendMsg);
writer.flush();

BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
mReceivedMsg = reader.readLine();
if(mReceivedMsg != null){
mMsgRev.setText(mReceivedMsg);
}else{
mMsgRev.setText("receive data error");
}

writer.close();
reader.close();
socket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}

3)、在AndroidManifest.xml中向服务器端的该文件一样,添加网络访问权限:<uses-permission android:name="android.permission.INTERNET"/>

5、执行环境搭建

服务端程序在开发板上执行,客户端程序在模拟器上执行,实现了基于Socket的数据收发。但是我这里只是进行了局域网内的通信,至于跨网络能不能行,目前条件不够,没法进行验证。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐