1、概念

  1. TCP/IP:属于传输层/网络层协议。手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接。TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。主要解决数据在网络中的传输。
  2. HTTP:即超文本传送协议(Hypertext Transfer Protocol ),属于应用层协议,是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。主要解决数据的包装与识别应用。
  3. Socket:本身并不是协议,而是一个调用接口(API)。可对TCP/IP协议进行封装和应用,可视为TCP/IP的编程接口。

2、模型

3、特点

3.1 TCP

存在三次握手、四次挥手。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

3.2 HTTP连接

最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。

3.3 套接字(socket)

通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远端主机的IP地址,远端进程的协议端口。

通常情况下Socket连接就是TCP连接,Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。

  套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

  1. 服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
  2. 客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
  3. 连接确认:当服 务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端 确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

3.4 TCP/UDP连接上的区别

  对于TCP连接:

  1.服务器端1)创建套接字create;2)绑定端口号bind;3)监听连接listen;4)接受连接请求accept,并返回新的套接字;5)用新返回的套接字recv/send;6)关闭套接字。

  2.客户端1)创建套接字create; 2)发起建立连接请求connect; 3)发送/接收数据send/recv;4)关闭套接字。

  TCP总结:

  Server端:create -- bind -- listen--  accept--  recv/send-- close

  Client端:create------- conncet------send/recv------close.

  对于UDP连接:

  1.服务器端:1)创建套接字create;2)绑定端口号bind;3)接收/发送消息recvfrom/sendto;4)关闭套接字。

  2.客户端:1)创建套接字create;2)发送/接收消息sendto/recvfrom;3)关闭套接字.

  UDP总结:

  Server端:create----bind ----recvfrom/sendto----close

  Client端:create----  sendto/recvfrom----close.

4、HTTP通信

HTTP(超文本传输协议),首先它是一个协议,并且是基于TCP/IP协议基础之上的应用层协议。TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,HTTP是应用层协议,主要解决如何包装数据。HTTP协议详细规定了浏览器与服务器之间相互通信的规则,是万维网交换信息的基础。HTTP是基于“请求-响应”形式并且是短连接,并且是无状态的协议。针对其无状态特性,在实际应用中又需要有状态的形式,因此一般会通过session/cookie技术来解决此问题。

5、URL通信与socket通信区别

5.1 利用 URL进行通信时

在服务器端常驻一个CGI程序,但它一直处于休眠状态。只有在客户端要求建立连接时才被激活,然后与用户进行通信。所以,在URL 通信方式中,服务器是被动等待连接通信的到来。

服务器端的程序只能与一个客户进行通信,形式比较单一。但是它不需要服务器端的CGI程序一直处于运行状态,只是在有客户申请时才被激活。所以,这种方式比较适用于客户机的浏览器与服务器之间的通信。

5.2 利用socket进行通信时

在服务器端运行一个socket通信程序。服务器端不停地监听某个端口,等待客户的连接申请,接到申请后建立连接并进行通信,所以,在socket通信方式中,服务器是主动等待连接通信的到来。

服务器端的程序可以打开多个线程与多个客户进行通信,还可以通过服务器使各个客户之间进行通信。这种方式比较灵活,适用于一些较复杂的通信,但是服务器端的程序必须始终处于运行状态以监听端口。

6、Socket通信

6.1 基于TCP协议的Socket

  • 服务器端:首先声明一个ServerSocket对象并且指定端口号,然后调用Serversocket的accept()方法接收客户端的数据。accept()方法在没有数据进行接收的处于堵塞状态。(Socket socket = serversocket.accept()),一旦接收到数据,通过inputstream读取接收的数据。
  • 客户端:创建一个Socket对象,指定服务器端的ip地址和端口号(Socket socket=new Socket("172.168.10.108",8080);),通过inputstream读取数据,获取服务器发出的数据(OutputStream outputstream=socket.getOutputStream()),最后将要发送的数据写入到outputstream即可进行TCP协议的socket数据传输。

6.2 基于UDP协议的数据传输

  • 服务器端:首先创建一个DatagramSocket对象,并且指点监听的端口。接下来创建一个空的DatagramSocket对象用于接收数据(byte data[]=new byte[1024]; DatagramSocket packet=new DatagramSocket(data, data.length)),使用DatagramSocket的receive方法接收客户端发送的数据,receive()与serversocket的accepet()类似,在没有数据进行接收的处于堵塞状态。
  • 客户端:也创建个DatagramSocket对象,并且指点监听的端口。接下来创建一个InetAddress对象,这个对象类似与一个网络的发送地址(InetAddress serveraddress=InetAddress.getByName("192.168.1.120")).定义要发送的一个字符串,创建一个DatagramPacket对象,并制定要讲这个数据报包发送到网络的那个地址以及端口号,最后使用DatagramSocket的对象的send()发送数据。*(String str="hello"; byte data[]=str.getByte(); DatagramPacket packet=new DatagramPacket(data, data.length, serveraddress,4567); socket.send(packet);)

6.3 Android基于TCP的socket通信DEMO

服务端:

 public class Main {
     private static final int PORT = 9999;
     private List<Socket> mList = new ArrayList<Socket>();
     private ServerSocket server = null;
     private ExecutorService mExecutorService = null; // 创建一个线程池

     public static void main(String[] args) {
         new Main();
     }

     public Main() {
         try {
             server = new ServerSocket(PORT);
             mExecutorService = Executors.newCachedThreadPool(); // 实例化一个线程池
             System.out.println("服务器已启动,等待加入...");
             Socket client = null;
             while (true) {
                 client = server.accept();
                 // 把客户端放入客户端集合中
                 mList.add(client);
                 mExecutorService.execute(new Service(client)); // 开启一个新线程
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }

     class Service implements Runnable {
         private Socket socket;
         private BufferedReader in = null;
         private String msg = "";

         public Service(Socket socket) {
             this.socket = socket;
             try {
                 in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                 // 客户端只要一连到服务器,便向客户端发送下面的信息。
                 msg = "服务器" + this.socket.getInetAddress() + "加入;此时总连接:" + mList.size() + "(服务器发送)";
                 this.sendmsg();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }

         @Override
         public void run() {
             try {
                 while (true) {
                     if ((msg = in.readLine()) != null) {
                         // 当客户端发送的信息为:exit时,关闭连接
                         if (msg.trim().equals("exit")) {
                             System.out.println("GAME OVER");
                             mList.remove(socket);
                             in.close();
                             msg = "服务器" + socket.getInetAddress() + "退出;此时总连接:" + mList.size() + "(服务器发送)";
                             socket.close();
                             this.sendmsg();
                             break;
                         } else {
                             // 接收客户端发过来的信息msg,然后发送给客户端。
                             msg = socket.getInetAddress() + ":" + msg + "(服务器发送)";
                             this.sendmsg();
                         }
                     }
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }

         /**
          * 循环遍历客户端集合,给每个客户端都发送信息。
          */
         public void sendmsg() {
             // 在服务器上打印
             System.out.println(msg);
             // 遍历打印到每个客户端上
             int num = mList.size();
             for (int i = 0; i < num; i++) {
                 Socket mSocket = mList.get(i);
                 PrintWriter out = null;
                 try {
                     out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())), true);
                     out.println(msg);
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
         }
     }
 }

客户端:

 public class MainActivity extends Activity {
     private TextView tv_msg = null;
     private EditText ed_msg = null;
     private Button btn_send = null;
     // private Button btn_login = null;
     private static final String HOST = "10.0.2.2";
     private static final int PORT = 9999;
     private Socket socket = null;
     private BufferedReader in = null;
     private PrintWriter out = null;
     private String content = "";
     private String temp = "";
     // 接收线程发送过来信息,并用TextView显示
     public Handler mHandler = new Handler() {
         public void handleMessage(Message msg) {
             super.handleMessage(msg);
             tv_msg.setText(content);
         }
     };

     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);

         tv_msg = (TextView) findViewById(R.id.tv_contents);
         ed_msg = (EditText) findViewById(R.id.et_content);
         btn_send = (Button) findViewById(R.id.bt_sender);

         new Thread(){
             public void run() {
                 try {
                     // 开启与服务器的socket连接
                     socket = new Socket(HOST, PORT);
                     in = new BufferedReader(new InputStreamReader(
                             socket.getInputStream()));
                     out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                             socket.getOutputStream())), true);

                     while (true) {
                         // 修改客户端主线程的数据
                         if (!socket.isClosed()) {
                             if (socket.isConnected()) {
                                 if (!socket.isInputShutdown()) {
                                     if ((temp = in.readLine()) != null) {
                                         content += temp + "\n";
                                         mHandler.sendMessage(mHandler.obtainMessage());
                                     } else {

                                     }
                                 }
                             }
                         }

                         // 向服务器传输数据
                         btn_send.setOnClickListener(new Button.OnClickListener() {

                             @Override
                             public void onClick(View v) {
                                 // TODO Auto-generated method stub
                                 String msg = ed_msg.getText().toString();
                                 if (socket.isConnected()) {
                                     if (!socket.isOutputShutdown()) {
                                         out.println(msg);
                                     }
                                 }
                             }
                         });
                     }
                 } catch (IOException ex) {
                     ex.printStackTrace();
                     ShowDialog("login exception" + ex.getMessage());
                 }
             };
         }.start();
     }

     /**
      * 如果连接出现异常,弹出AlertDialog!
      */
     public void ShowDialog(String msg) {
         new AlertDialog.Builder(this).setTitle("notification").setMessage(msg)
                 .setPositiveButton("ok", new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {

                     }
                 }).show();
     }

     public void exit(View view){
         onDestroy();
     }

     @Override
     protected void onDestroy() {
         // TODO Auto-generated method stub
         try {
             out.flush();
             out.close();
             socket.close();
         } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }
 }

客户端布局文件:

 <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"
     tools:context="com.example.socketclient.MainActivity" >

     <TextView
         android:id="@+id/tv_contents"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@string/hello_world" />

     <EditText
         android:id="@+id/et_content"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:inputType="text" />

     <LinearLayout
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal" >

         <Button
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:onClick="exit"
             android:text="退出(C)" />

         <Button
             android:id="@+id/bt_sender"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="发送(S)" />
     </LinearLayout>

 </LinearLayout>

7、拓展

7.1 TCP/UDP区别

  • TCP有连接;UDP无连接
  • TCP面向连接;UDP面向数据
  • TCP关心返回数据;UDP一次性,发出即结束
  • TCP数据传输可靠(超时重发机制;所占资源多);UDP则相对不可靠(所占资源少)

7.2 HTTP/HTTPS区别

  • https协议需要到ca申请证书,一般免费证书很少,需要交费。
  • http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
  • http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

7.3 长连接/短连接区别

  1. 长连接: 指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接;一般需要自己做在线维持。
  2. 短连接: 指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接;一般银行都使用短连接。它的优点是:管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段

  比如http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。其实长连接是相对于通常的短连接而说的,也就是长时间保持客户端与服务端的连接状态。

长连接与短连接的操作过程 

  1. 通常的短连接操作步骤是:连接→数据传输→关闭连接;
  2. 而长连接通常就是:连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接;

  这就要求长连接在没有数据通信时,定时发送数据包(心跳),以维持连接状态,短连接在没有数据传输时直接关闭就行了

什么时候用长连接,短连接?

  长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,下次次处理时直接发送数据包就OK了,不用建立TCP连接。

  例如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。

http://jingyan.baidu.com/article/08b6a591e07ecc14a80922f1.html

http://blog.csdn.net/maoxiao1229/article/details/22886337

http://blog.csdn.net/zeng622peng/article/details/5546384

http://blog.csdn.net/lanhuzi9999/article/details/32713815

http://blog.chinaunix.net/uid-26000296-id-3758651.html

Android之从TCP/IP、HTTP看Socket通信的更多相关文章

  1. JAVA基础知识之网络编程——-TCP/IP协议,socket通信,服务器客户端通信demo

    OSI模型分层 OSI模型是指国际标准化组织(ISO)提出的开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM),它将网络分为七 ...

  2. http、TCP/IP协议与socket之间的区别

    http.TCP/IP协议与socket之间的区别     网络由下往上分为:  www.2cto.com   物理层--                       数据链路层-- 网络层--   ...

  3. http、TCP/IP协议与socket之间的区别(转载)

    http.TCP/IP协议与socket之间的区别  https://www.cnblogs.com/iOS-mt/p/4264675.html http.TCP/IP协议与socket之间的区别   ...

  4. Http TCP/IP协议和socket之间的区别和联系

    总结,TCP/IP是传输层协议,主要解决数据如何在网路中传输,socket是TCP/IP协议的具体实现,是对TCP/IP协议的封装和应用,属于程序员层面,HTTP是应用层协议,应用层协议很多,类似的像 ...

  5. tcp连接是基于socket通信的吗

    https://zhidao.baidu.com/question/1305788160020716299.html ------ 网络七层协议 五层模型 TCP连接 HTTP连接 socket套接字 ...

  6. TCP/IP基础概念及通信过程举例

    TCP/IP基础概念及通信过程举例 出现 上个世纪60年代,由于中央集中式网络的容灾性较弱,以美国国防部为中心的一家组织研究出分组交换网络.后来为了验证分组交换技术的实用性,ARPANET出现了,并且 ...

  7. Linux TCP/IP 协议栈之 Socket 的实现分析(一)

    内核版本:2.6.37参考[作者:kendo的文章(基于内涵版本2.6.12)] 第一部份 Socket套接字的创建 socket 并不是 TCP/IP协议的一部份. 从广义上来讲,socket 是U ...

  8. 网络基础之 tcp/ip五层协议 socket

    1 网络通信协议(互联网协议) 1.1 互联网的本质就是一系列的网络协议 1.2 osi七层协议 1.3 tcp/ip五层模型讲解 1.3.1 物理层 1.3.2 数据链路层 1.3.3 网络层 1. ...

  9. c# TCP/IP协议利用Socket Client通信(只含客户端Demo)

    完全是基础,新手可以随意看看,大牛可以关闭浏览页了,哈哈. TCP/IP协议 TCP/IP是一系列网络通信协议的统称,其中最核心的两个协议是TCP和IP.TCP称为传输控制协议,IP称为互联网络协议. ...

随机推荐

  1. MemCahced 使用及常见问题说明

    前言 本文档是针对Memcached使用及常见问题的说明. 一.获取 1. MemCached 官网:http://www.memcached.org 下载:http://memcached.org/ ...

  2. 11) 生成可执行jar文件 maven-shade-plugin

    搜索 site:maven.apache.org maven-assembly-plugin http://maven.apache.org/plugins/maven-assembly-plugin ...

  3. iOS中清除缓存的方法 以及SDWebimage自带的清除缓存方法

    1  SDWebimage中 (1)  计算缓存的大小 单位 : (MB) CGFloat size = [[SDImageCache sharedImageCache] getSize] / 102 ...

  4. Ubuntu安装教程(双系统)

    经常要重装还不如写个安装教程省的每次都要查 Ubuntu安装教程: win7下安装Linux实现双系统全攻略:https://jingyan.baidu.com/article/c275f6bacc3 ...

  5. day15(mysql之零碎知识)

    数据完整性 实体完整性 实体: 表中一行(一行记录)代替一个实体 实体完整性的作用: 标识每一行数据不重复. 约束类型: 主键约束, 唯一约束,自动增长列. 主键约束: 标识该列唯一,非空. 注:   ...

  6. 挂载Linux云主机硬盘到本地计算机

      现在移动硬盘已经是每个人的生活必需品了,当然网络也是我们生活的必需品,我们现在就是要用网络存储代替硬盘存储,当然再实际使用过程中需要考虑到以下两个问题: 网络延迟 云主机磁盘IO   以上两个关键 ...

  7. Android 实现界面(Activity)的跳转

    界面跳转 如,我想重一个界面A跳转到界面B,可以用,setContentView(R.layout.activity_login); 但是他其实只是将改界面铺在了最顶层,而按menu这些菜单其实还是底 ...

  8. javascript中的with关键字

    说起js中的with关键字,很多小伙伴们的第一印象可能就是with关键字的作用在于改变作用域,然后最关键的一点是不推荐使用with关键字.听到不推荐with关键字后,我们很多人都会忽略掉with关键字 ...

  9. 关于微信小程序登录,后端如何生成3rd_session?(后端为c#)

    各位大神,请教一个问题,现在是小程序端调用wx.login后,将code传入后端接口,后端发起微信服务器request获取openid和session_key,后端再自定义生成一个登录状态:3rd_s ...

  10. jwt的ASP.NET MVC 身份验证

    Json Web Token(jwt)      一种不错的身份验证及授权方案,与 Session 相反,Jwt 将用户信息存放在 Token 的 payload 字段保存在客户端,通过 RSA 加密 ...