socket编程是网络通信的一个基础应用。不管是手机端还是PC端都须要socket技术来建立网络通信。

在本章小编主要从下面几个方面来介绍socket的相关知识:

各自是“什么是socket?”,“socket有什么特点?”,“socket与Http以及TCP的差别”。“移动端socket的Demo”。写的不好的地方请大家批评指正。

一、何为socket?

socket也被称为“套接字”。它是一种网络通信的方式,它不是一种协议,而是提供给程序猿实现TCP/IP封装与传输数据的接口。

用于在client和服务端之间建立一个通信管道,使得应用程序/client能够通过这个通信管道向server/还有一台主机发送请求,同一时候server也能够进行对应,建立两者之间的传输数据与交换。

在Android中,我们知道每一个应用程序都能够使用多线程来进行操作,用于网络传输的app的多个线程能够都建立一个socket连接。每一个线程维护自己的socket管道,从而实现并发的网络通信。

socket的组成部分主要包含5个:连接使用的协议(TCP/UDP),clientIP,clientport号,server端IP地址。server端的port号。在Android中,serverSocket用于server端而socket是用于建立网络连接时用的,在连接成功时两端都会产生一个socket对象。

二、socket的特点及通信原理

我们能够看到。一个socket建立时所使用的协议能够是TCP的。也能够是UDP的。

TCP是可靠的而UDP是不可靠的,原因就是TCP建立时须要三次握手。两方建立通信管道才干够传输数据,且是双向的。

而UDP在传输数据时仅仅是把应用层发来的数据进行打包而且附上目的的地址,不负责对方是否接收到。

一个Socket的通信建立能够分为client和服务端两部分:
服务端:1、创建server套接字并绑定到自己的一个port上,这个port最好大于1024,由于0~1023port号是被系统预留的,会被一些系统功能所调用。
2、建立套接字的监听器。监听是否有别的client程序来请求訪问本port的serverSocket。
3、假设接受到,则接受请求建立连接通信


client:1、创建一个client套接字,绑定要訪问的目标server的IP地址及port号
2、连接服务端(这里与PC上的socket连接不同。不须要connect(),由于Android上的clientsocket在创建时,假设创建成功会自己主动内部调用连接方法)
                3、与服务端进行通信
4、主动关闭clientsocket
了解了client与服务端的通信过程,我们都能了解到:服务端事实上一直保持着监听client请求的状态。socket连接仅仅能由发起请求的client主动关闭。两端在进行通信的时候,数据是通过InputStream和OutputStream来实现的,且首先是服务端收到输入流。再将结果通过输出流返回给client。

而client方面是先发送输出流,再接收到输入流。

大致模式例如以下:
                      
server和client的连接:server监听------->client请求------->建立连接

三、socket与HTTP、TCP的差别

首先须要知道HTTP是应用层协议,主要解决的是怎样包装数据。而TCP是传输层协议。主要解决的是怎样数据传输。socket是TCP/IP协议的封装,本身并非协议。

socket的连接模式与HTTP、TCP的连接模式不一致。

从上节已经了解到socket的连接是从server监听開始的,而在TCP方面,client与server的连接须要经过三次握手之后才正式開始数据的传输,而HTTP则是基于"请求-响应"才干建立传输数据,什么意思呢?仅仅有先请求,server才干对外发数据,不能主动建立传输。在HTTP经过了0.9、1.0和1.1时代,这样的连接模式能够在一次TCP连接建立时一直保持。响应多次请求。

当socket是传输层的一个封装,传输层主要由TCP和UDP协议,当socket使用的是TCP协议而不是UDP协议时。一个socket连接事实上就是TCP连接。

四、Demo

这里我们将创建一个demo,在Android上使用socket。

我们的Demo主要功能是在编辑框中编写一段文字,然后按发送button。最后内部实现通过socket的通信方式。反馈到textview上进行显示编辑的内容。里面的细节重点会在末尾处分析。

以下是xml布局文件:
        android:id="@+id/btn_conn"/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="请在这里编辑要发送的内容"
android:id="@+id/et_message"/> <Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="发送"
android:id="@+id/btn_sent"/> <TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/tv"
android:hint="接收发来的数据"/>
</LinearLayout>

布局效果例如以下:



首先来描写叙述下我们要实现的功能逻辑:
1、通过点击连接先建立socket通信管道
2、在编辑框中输入我们要发送的内容,按下发送button,数据会显示到文本控件中。
3、在内部自己建立一个线程,不能在UI线程中更新,会造成ANR;
4、本身即作为发送方,又作为接收方,主要过程是把数据打包发送,通过outputstream进行输出传输。创建为消息的内容;接着被handler收到,扔进消息队列,处理的时候再把数据解压。进行ui更新。主要功能handler.sentmessage()和handler.handmessage()。还有就是outputstream和inputstream时的数据打包,encoding必须一致。

中文能够使用GB2312.


代码例如以下:
package com.example.mysocketdemo;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException; import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Build; public class MainActivity extends Activity {
private TextView tv;
private Button btnsent,btnconn;
private EditText ed_message;
private OutputStream output;
private Socket clientSocket;
private Handler mHandler;
private MyThread mythread;
boolean stop = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
init();
//onClickEvent---connect
btnconn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
clientSocket = new Socket("127.0.0.1", 8888);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "connect ok", Toast.LENGTH_SHORT).show();
//把socket绑定到自己的线程对象
try {
mythread = new MyThread(clientSocket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mythread.start();//启动线程 //更新UI,大部分的数据工作已经交给了mythread对象
btnsent.setEnabled(true);
btnconn.setEnabled(false);
stop = false;
}
});
//sent Message
btnsent.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
//当点击button时,会获取编辑框中的数据,然后提交给线程
//先将发送内容进行打包
byte[] msgBuffer = null;
try {
msgBuffer = ed_message.getText().toString().getBytes("GB2312");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//打包完毕之后,加入socket的输出流对象
try {
output = clientSocket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//输出流对象将字节写入
//不管是输出流还是输入流。操作的都是字节,假设向变成字符串,须要自己构建String对象
output.write(msgBuffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "发送成功", Toast.LENGTH_SHORT).show();
ed_message.setText("");
}
}); //在连接和发送数据之后。接下来就是处理了,发送的数据会通过message的方式传递到消息队列,再由handl进行获取
mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
tv.setText(msg.obj.toString());
};
};
}
public void init()
{
tv = (TextView) findViewById(R.id.tv);
btnsent = (Button) findViewById(R.id.btn_sent);
ed_message = (EditText) findViewById(R.id.et_message);
btnconn = (Button) findViewById(R.id.btn_conn);
btnconn.setEnabled(true);
btnsent.setEnabled(false);
} //自己定义线程类;
private class MyThread extends Thread{
//构建自己的socket对象,用来在线程内使用
private Socket socket;
private byte[] buf = null;
private InputStream inputstream;
String str = null;
public MyThread(Socket socket) throws IOException
{
this.socket = socket;
inputstream = this.socket.getInputStream();
}
@Override
public void run() {
// TODO Auto-generated method stub
while(!stop)
{
buf = new byte[512];
//将inputstream内的数据读到buf里
try {
this.inputstream.read(buf);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//将buf里的字符流进行解析,得到
this.str = new String(buf, "GB2312").trim();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//线程内获取了来自socket的Inputstream字节流,而且转换成字符串后,线程就获取了消息的实体内容
//此时线程将运行自己的一个使命。就是创建消息,并发送出去
Message msg = new Message();
msg.obj = this.str;
mHandler.sendMessage(msg);
}
}
} @Override
protected void onDestroy() {
// TODO Auto-generated method stub
if (mythread!=null) {
mythread.interrupt();
}
super.onDestroy();
}


了解代码的逻辑之后。我再理一下整个思路:
当我们点击了connnet之后。就会创建连接目标ip地址及port的socket连接,此时,什么数据都没有,socket的Outputstream和InputStream里面都是空的。虽然我们自己定义的线程在连接后就启动了,而且必须运行run方法,可是此时没有数据来接收。
当我们编辑好文笔点击了sentbutton之后。编辑框里的文本会由字符串向字节的包装,使用的是String.getbyte()方法。为啥呢,由于outputstream和inputstream仅仅接受字节流的数据。

当socket的getOutputStream获取了outputstream对象之后,运行了write方法进行数据的写入,而此时线程依旧在运行,它突然发现连接的socket里有数据了,就使用getIupteStream获取了inputstream对象,採用了read方法读取了字节流,最后打包成字符串。

打包成字符串之后,线程要运行一个自己的使命。就是将其封装成消息。以消息的形式塞给主线程的消息队列。此时UI线程的使者Hanlder就完毕了sendmessage的任务。

最后回到主线程,Handler对象使用handlmessage方法将消息的内容显示在了textView上。


以上就是整个逻辑。



Android网络应用之Socket(一)的更多相关文章

  1. Android 网络编程 Socket

    1.服务端开发 创建一个Java程序 public class MyServer { // 定义保存所有的Socket,与客户端建立连接得到一个Socket public static List< ...

  2. Android中基于Socket的网络通信

    1. Socket介绍 2. ServerSocket的建立与使用 3. 使用ServerSocket建立聊天服务器-1 4. 使用ServerSocket建立聊天服务器-2 5. 在Android中 ...

  3. Android 网络编程 Socket Http

    前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net        ...

  4. 在Android上使用Socket

    原文地址:http://www.cnblogs.com/kross/p/3621952.html 考虑到以后可能要用到这方面的知识,就来写个Demo尝试下,其实以前学过,但不记得了……(用不到的东西各 ...

  5. Android 网络通信之Socket

    Android 网络通信之Socket 应用软件的网络通信无非就是Socket和HTTP,其中Socket又可以用TCP和UDP,HTTP的话就衍生出很多方式,基础的HTTP GET和POST请求,然 ...

  6. 【Android实战】Socket消息通信

    这篇博客的内容是基于http://my.oschina.net/fengcunhan/blog/178155进行改造的.所以须要先看完这篇博客,然后再来看以下的内容. 1.须要完毕的功能是直播间的so ...

  7. Android进程间通信之socket通信

    用Java中的socket编程. 通过socket实现两个应用之间的通信,可以接收和发送数据,同时将接收到的数据显示在activity界面上. Server端: ServerLastly.java p ...

  8. [Android] HttpURLConnection & HttpClient & Socket

    Android的三种网络联接方式 1.标准Java接口:java.net.*提供相关的类//定义地址URL url = new URL("http://www.google.com" ...

  9. android中利用Socket实现手机客户端与PC端进行通信

    1. 项目截图

随机推荐

  1. Android 为什么要有handler机制?handler机制的原理

    为什么要有handler机制? 在Android的UI开发中,我们经常会使用Handler来控制主UI程序的界面变化.有关Handler的作用,我们总结为:与其他线程协同工作,接收其他线程的消息并通过 ...

  2. vsphere client 参数

    转自:http://blog.163.com/sword_111/blog/static/66589416201422964544918/ C:\Program Files (x86)\VMware\ ...

  3. 字符串中的空格替换问题(Java版)

    解决方式一:时间复杂度为O(n^2) 解决方式二:时间复杂度为O(n) 代码实现: package string; public class SpaceStringReplace2 { //len为数 ...

  4. Android Studio - no debuggable applications 的解决的方法

    之前logcat总是无法显示调试应用的信息 曾经我都是卸载重装.后来发如今StackOverflow有一个哥们说的非常对.一次就成功. 原话是这么说的: You also should have To ...

  5. (win7/8/10)鼠标右键添加按下SHIFT键时弹出带管理员权限的“在此处打开命令窗口”

    Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Directory\Background\shell\runas]@="@sh ...

  6. thinkphp3.1课程 1-2 thinkphp中入口文件的实质是什么

    thinkphp3.1课程 1-2 thinkphp中入口文件的实质是什么 一.总结 一句话总结:在thinkphp中,我们访问的始终是入口文件,并没有主动去访问任何一个其他文件,只不过在入口文件体内 ...

  7. 【奇葩笔试】—— printf() 作为函数的参数及其返回值

    int f(int a, int b, int c){ return 0; } int main(int, char**){ f(printf("a"), printf(" ...

  8. rabbitmq.config详细配置参数

    原文:rabbitmq.config详细配置参数 rabbitmq.config详细配置参数 详细使用方法请点击:http://blog.csdn.net/Super_RD/article/detai ...

  9. 用IBM WebSphere DataStage进行数据整合: 第 1 部分 分类: H2_ORACLE 2013-08-23 11:20 688人阅读 评论(0) 收藏

    转自:http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0602zhoudp/ 引言 传统的数据整合方式需要大量的手工 ...

  10. 批量杀死MySQL连接的几种方法

    法一: 通过information_schema.processlist表中的连接信息生成需要处理掉的MySQL连接的语句临时文件,然后执行临时文件中生成的指令.   mysql> select ...