Android基于Socket和Http的网络编程

基于SocketHttp的网络编程

一、基于Socket套接字的网络编程

网络应用程序的开发有很多的架构和模式,常见的有C/SB/S等,而Socket主要就是用于进行传统的C/S模式应用的开发。C/S模式中主要需要开发两个端,服务端和客户端,工作原理如下:

 

如上图所示:

1、首先服务器端启动,监听指定的连接端口等待客户端的连接数据请求;

2、客户端请求成功,连接到服务器的指定端口等待交互;

3、服务器端接收到来自客户端的连接请求,建立连接等待交互;

4、服务端和客户端同时打开一个输入流和输出流,客户端的输入流对应着服务端返回的输出流,相反客户端的输出流对应着服务端的输入流;

5、客户端和服务端通过输入输出流进行双向的消息通信;

6、通信结束后,客户端和服务端各自关闭本次连接;

上面是基本的原理,是很简单吧!实际内部的通信机制是比较复杂的,这里只针对如何使用Socket进行网络编程,对于内部的通信实现不进行介绍,有兴趣的读者可以参考相关资料。

实例如下:

我们知道Android应用程序使用Java语言编写开发的,因此在Android平台下开发C/S模式程序较简单,直接使用Java中的SocketServerSocket类即可。这种方式与传统的网络套接字开发几乎没有区别,我想熟悉Java的游者应该很容易接受吧。

服务端:

首先我们需要新建一个Java项目作为服务器端,代码如下:

/*

 * 服务器端代码实现

 * */

public class SocketServer {

private static ServerSocket mServer;// 服务端口类引用

private static boolean flag = true;

public static void main(String[] args) {

try {

// 创建服务端及端口

mServer = new ServerSocket(8888);   System.out.println("正在监听8888端口....");

while(flag) {// 创建Socket对象 监听服务端端口的访问Socket socket = mServer.accept();

DataInputStream dis=new DataInputStream(socket.getInputStream());// 双向流创建

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

System.out.println("客户端信息:"+ dis.readUTF());// 读取客户端请求

dos.writeUTF("成功连接到服务器!");

dis.close();// 关闭输入输出流及端口

dos.close();

socket.close();

}

catch (IOException e) {

e.printStackTrace();

}

}

}

服务端启动效果如下:

客户端:

新建一个Android项目作为客户端请求服务器,代码如下:

布局文件main.xml如下:

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    android:background="#898989"

    tools:context=".SocketClient" >

    <EditText 

        android:id="@+id/connect_input"

        android:layout_width="200dp"

        android:layout_height="20dp"

        android:layout_centerHorizontal="true"

        android:background="#ffffff"/>

    <Button

        android:id="@+id/connect_btn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="connect to the server" 

        android:layout_alignLeft="@id/connect_input"

        android:layout_below="@id/connect_input"/>

    <TextView 

        android:id="@+id/connect_value"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:textColor="#000000"

        android:layout_below="@id/connect_btn" 

        android:text="test"

        android:layout_alignLeft="@id/connect_btn"/>

</RelativeLayout>

/*

 * 客户端由手机充当

 * */

public class SocketClient extends Activity {

EditText connectEdt;

Button connectBtn;

TextView connectText;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

initView();

}

private void initView() {

connectEdt = (EditText) findViewById(R.id.connect_input);

connectText = (TextView) findViewById(R.id.connect_value);

connectBtn = (Button) findViewById(R.id.connect_btn);

connectBtn.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

connectToServer();// 连接到服务器方法

}

});

}

private void connectToServer() {

String serverIP = "192.168.1.6";// 本机的IP设定

try {

Socket socket = new Socket(serverIP,8888);// 创建Socket套接字 并发出连接请求

DataInputStream dis = new DataInputStream(socket.getInputStream());// 双向流创建

DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

String strInput = connectEdt.getText().toString();// 获取发送到服务端的信息

dos.writeUTF(strInput);// 写信息到输出流

connectText.setText(dis.readUTF()); // 从输入流中获得信息

dis.close();

dos.close();

socket.close();

catch (UnknownHostException e) {

e.printStackTrace();

catch (IOException e) {

e.printStackTrace();

}

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.socket_client, menu);

return true;

}

}

注意:

在创建Socket套接字的时候需要指明服务端的IP和端口号,这里的IP为我们计算机的真实IP而不是使用环回地址“127.0.0.1”,因此运行本程序需要根据自己的实际IP来修改服务器端的IP;另外,不要忘了在我们的AndroidManifest.xml中配置好网络访问权限。

客户端发送内容到服务器效果如下:

服务器端显示效果如下:

至此,我们就成功的完成了基于Socket的网络编程了,很简单吧!

二、基于Http协议的网络编程

我们知道Http协议(超文本传输协议)是基于TCP/IP协议的协议,是WEB浏览器和WEB服务器端的应用层协议,也是通用的,无状态的,面向对象的通信协议。我们还知道,WWW应用系统是以internet作为传输媒介的,而且这个系统上的传输单位是网页,同时它是基于B/S模式的,有WEB浏览器和WEB服务器构成的,他们之间使用Http超文本协议进行相互通信的。

一次HTTP操作称为一个事务,其工作过程可分为四步:

1)首先客户机与服务器需要建立连接。

2)建立连接后,客户机Socket形式发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。

3)服务器接到请求后,进行相应的事物处理,然后给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。

4)客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。

如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,HTTP协议永远都是客户端发起请求,服务器回送响应

实例如下:

URLConnection的使用

下面我们就是用基于Http协议相关的简单应用,即通过URLConnectiton来获得谷歌或百度页面的内容。

代码如下:

/*

 * 使用HttpURLConnection获取网络资源

 * */

public class HttpURLAct extends Activity {

ScrollView scrollView = null;

TextView textView = null;

URLConnection ucon = null;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

scrollView = new ScrollView(this);

textView = new TextView(this);

BufferedInputStream bis = null;

ByteArrayBuffer bab = null;

String url_str = "http://www.google.cn/";// 资源标识符

try {

URL url = new URL(url_str);// 初始化URL

ucon = url.openConnection();// 建立与服务器的连接

bis = new BufferedInputStream(ucon.getInputStream());// 通过连接得到输入流

int c = 0;

bab = new ByteArrayBuffer(1000);

while((c=bis.read())!= -1) {

bab.append((char)c);// 将接收到的信息放入到字节缓冲数组中

}

catch (MalformedURLException e) {

e.printStackTrace();

catch (IOException e) {

e.printStackTrace();

finally {

if(bis != null) {

try {

bis.close();

bis = null;

catch (IOException e) {

e.printStackTrace();

}

}

}

String result = EncodingUtils.getString(bab.toByteArray(), "UTF-8");

textView.setText(result);// 显示得到的信息

scrollView.addView(textView);

setContentView(scrollView);

}

}

注意:别忘了,应该现在AndroidManifest.xml中配置访问网络的权限,即添加<uses-permission andorid:name=android.permission.INTERNET/>

运行效果图如下(是一个网络传输的页面数据):

另外,我们一般从网络上获得的数据大多为XML或是JSON格式的数据,对于这两种的格式的数据的解析和创建,我会在相关章节更新。

HttpClient的简单使用:

在这里,我们使用Android自带的HttpClient来获得网站数据。即使用POST方式来获得网站的数据,而另一个使用GET方式来获得数据,然后用TextView显示出来由服务器返回的数据内容。

代码如下:

/*

 * HttpClient简单使用

 * */

public class HttpClientAct extends Activity {

private TextView text;

private Button get;

private Button post;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

text = (TextView) findViewById(R.id.text_show);

get = (Button) findViewById(R.id.get_content);

post = (Button) findViewById(R.id.post_content);

OnClickListener c = new OnClickListener(){

public void onClick(View v) {

if(v == get) {// Http Get方式联机

method_get();

}

else if(v == post) {// Http Post方式联机

method_post();

}

}

};

get.setOnClickListener(c);

post.setOnClickListener(c);

}

private void method_get() {

String uri = "http://www.xxxx.cc:8751/index.php?str=I+am+Get+String";

HttpGet httpRequest = new HttpGet(uri);

// 发出httpRequest请求并接受返回的结果

try {

HttpResponse httpResponse = new DefaultHttpClient().execute(httpRequest);

// 如果返回的状态码为200则访问成功

if(httpResponse.getStatusLine().getStatusCode() == 200) {

// 获得返回的字符串

String result = EntityUtils.toString(httpResponse.getEntity());

// 去除冗余字符串

result = str_replace("(\r\n|\r|\n|\n\r)","",result);

// 显示返回的内容

text.setText(result);

}

else {

text.setText("error response:"+ httpResponse.getStatusLine().toString());

}

catch (ClientProtocolException e) {

e.printStackTrace();

catch (IOException e) {

e.printStackTrace();

}

}

private void method_post() {

String uri = "http://www.xxxx.cc:8751/Android/Test/API/Post/index.php";

HttpPost httpRequest = new HttpPost(uri);

// 当以Post方式发送请求时,必须使用NameValuePair数组

List<NameValuePair> params = new ArrayList<NameValuePair>();

params.add(new BasicNameValuePair("str","I am Post String"));

// 发送请求

try {

httpRequest.setEntity(new UrlEncodedFormEntity(params,HTTP.UTF_8));

HttpResponse httpResponse;

httpResponse = new DefaultHttpClient().execute(httpRequest);

// 如果返回的状态码为200则访问成功

if(httpResponse.getStatusLine().getStatusCode() == 200) {

// 获得返回的字符串

String result = EntityUtils.toString(httpResponse.getEntity());

// 去除冗余字符串

result = str_replace("(\r\n|\r|\n|\n\r)","",result);

// 显示返回的内容

text.setText(result);

}

else {

text.setText("error response:"+ httpResponse.getStatusLine().toString());

}

catch (UnsupportedEncodingException e) {

e.printStackTrace();

catch (ClientProtocolException e) {

e.printStackTrace();

catch (IOException e) {

e.printStackTrace();

}

}

private String str_replace(String from,String to,String target) {

String pattern = "(?i)" + from;

Pattern p = Pattern.compile(pattern);

Matcher m = p.matcher(target);

if(m.find()) 

return target.replaceAll(from, to);

else 

return target;

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.http_client, menu);

return true;

}

注意:别忘了,应该现在AndroidManifest.xml中配置访问网络的权限,即添加<uses-permission andorid:name=android.permission.INTERNET/>

另外,上面的URL地址要是有效的才可以得到服务器端的正常返回。当然,这个是经过我验证的,没有问题的。

效果图如下:

上面简单的介绍了在Android中基于Http协议的网络编程的简单使用,在上面我们使用了URLConnectionHttpClient来与服务器端进行沟通的验证,许多其他的复杂的网络通信都是以上面的为基础进行的。

当然,还有很多其他的相关内容,会在空余时间继续更新。

技术讨论群:179914858

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云水之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值