Socket通信原理及举例

大家或多或少的都听过Socket这个单词,我们都知道Socket是用于网络通讯中的某个步骤,那么Socket到底是怎么一回事呢?我们下面来仔细说一下。

TCP/IP协议

要想理解Socket,那么就不得不先熟悉一下TCP/IP协议族。

TCP/IP(Transmission Control Protocol/Internet Protocol),既传输控制协议/网间协议,定义了主机如何接入因特网以及网络数据是如何在它们之间传播的。TCP/IP协议参考模型吧所有的TCP/IP系列协议归类到四个抽象层中:

  • 应用层:TFTP, HTTP, SNMP, FTP, SMTP, DNS, Telnet等等
  • 传输层:TCP, UDP
  • 网络层:IP, ICMP, OSPF, EIGRP, IGMP
  • 数据链路层:SLIP, CSLIP, PPP, MTU

而Socket是在应用层之下、传输层之上的一个接口层。是操作系统提供给用户访问网络的系统接口,我们可以借助于Socket接口层,对传输层、网络层以及数据链路层进行操作,来实现我们不同的应用层协议。对于应用层,我们想实现网络功能,归根到底都是要通过Socket来实现的。

TCP和UDP

  • UDP (User Data Protocol,用户数据协议):数据报通信协议。UDP是一种无连接的协议,这就意味着我们每次发送数据报时,需要同时发送本机的socket描述符和接收端的socket描述符。因此,我们在每次通信时都需要发送额外的数据。

  • TCP (Transfer Control Protocol,传输控制协议):流通讯协议,TCP是一种基于连接的协议。在使用流通信之前,我们必须在通信的一对儿socket之间建立连接。其中一个socket作为服务器进行监听连接请求。另一个则作为客户端进行连接请求。一旦两个socket建立好了连接,他们可以单向或双向进行数据传输。

  • UDP和TCP的区别:两者最大的区别在于,TCP是可靠的,也就是说,我们通过TCP发送的数据,网络协议栈会保证数据可靠的传输到对端,而UDP是不可靠的,如果出现丢包,协议栈不会做任何处理,可靠性的保证交由应用层处理。因此,TCP的性能会比UDP低,但是可靠性会比UDP好很多。

Android中实现Socket

Socket是进程间通讯的一种方式,被广泛的应用于网络间进程间通讯。Socket起源于Unix,是基于Unix的基本思想”一切皆文件”来设计的。所以Socket是一种特殊的文件,一些Socket函数也是对这个文件进行的操作(读/写IO、打开、关闭)。

Socket既然可以跨设备进行通讯,那么自然可以在同一个设备上通讯,这里我们通过一个Android的小demo来实现Socket通讯。

这个小程序实现了一个模拟聊天的功能,客户端发送消息到服务端,服务端收到消息后,返回一个随机的回复语到客户端,这些对话会显示到屏幕上。

  • 客户端编写(源码)
    1. 开启Socket

      在客户端启动一个Socket的方法十分简单:

      //连接Socket
      String host = "localhost";
      int port = 8688;
      socket = new Socket(host, port);

      上面代码中,host即客户端需要连接的集齐,port就是服务端用来监听的请求端口。注意1024以内端口都是系统预留端口,这些端口为一些常用的服务所使用,比如邮件、FTP和HTTP。所以服务端的端口选择要大于1024。

    2. 写入数据

      从客户端的socket对象中得到OutputStream对象,然后写入数据,类似文件的IO操作:

      try {
       //连接Socket
       String host = "localhost";
       int port = 8688;
       socket = new Socket(host, port);
       //从Socket中获取输出流
       printWriter = new PrintWriter(new BufferedWriter(
               new OutputStreamWriter(socket.getOutputStream())),
               true);
       //发送连接成功消息,使button可点击
       handler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
       Log.d(TAG, "connect server success");
      } catch (IOException e) {
       SystemClock.sleep(1000);
       Log.e(TAG, "connect tcp server failed,retry ... ");
      
      }
    3. 获取服务端返回数据

      此时我们已经发送消息到服务端,然后我们需要等待服务端返回的消息

      try {
       //获取服务端的回复数据流
       BufferedReader br = new BufferedReader(
               new InputStreamReader(socket.getInputStream()));
       while (!TCPClientActivity.this.isFinishing()) {
           //读取回复的消息
           String msg = br.readLine();
           Log.d(TAG, "receive:" + msg);
           //回复的消息拼接格式后,输出到客户端
           if (msg != null) {
               String time = formatDateTime(System.currentTimeMillis());
               final String showedMsg = "server " + time + ":" + msg + "\n";
               handler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showedMsg).sendToTarget();
           }
       }
       Log.d("TAG", "quit...");
       MyUtils.close(printWriter);
       MyUtils.close(br);
       socket.close();
      } catch (IOException e) {
       e.printStackTrace();
      }

      这里需要注意的是:在Android中,是不允许在主线程进行网络通讯的,所以我们需要在新的线程中进行socket操作,然后操作完成后调用Handler来更新UI,感兴趣的同学可以查看对应的源码。

    4. 关闭IO对象

      最后在onDestory中,我们需要关闭对应的流对象,以确保资源的正确释放

      protected void onDestroy() {
       //退出时候销毁对应流
       if (clientSocket != null) {
           try {
               clientSocket.shutdownInput();
               clientSocket.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       super.onDestroy();
      }
  • 服务端编写(源码)
    1. 打开服务端Socket

      下面代码我们创建了一个服务端的socket,然后调用accept方法来监听并获取客户端的请求socket。accept方法是一个阻塞方法,在服务端和客户端之间 建立联系之前会一直等待阻塞。

      ServerSocket serverSocket = new ServerSocket(8688);
      Socket client = serverSocket.accept();
    2. 读取数据

      得到client对象以后,我们就可以像文件操作一样来读取文件了,由于这里是个聊天室demo,所以我们加入while循环来不断获取客户单的消息

      ServerSocket serverSocket = null;
      try {
       //建立一个端口为8688的服务
       serverSocket = new ServerSocket(8688);
      } catch (IOException e) {
       Log.e(TAG, "establish tcp server failed,port:8688");
       e.printStackTrace();
       return;
      }
      
      while (!isServiceDestoryed) {
       try {
           //连接客户端Socket
           final Socket client = serverSocket.accept();
           Log.d(TAG, "accept");
           new Thread() {
               public void run() {
                   try {
                       //回复客户端
                       responseClient(client);
                   } catch (IOException e) {
                       e.printStackTrace();
                   }
               }
           }.start();
       } catch (IOException e) {
           e.printStackTrace();
       }
      }

      同样的,上述方法也需要运行在非UI线程中。

    3. 回传数据到客户端

      在上述代码中的回复客户端的方法,具体操作如下:

      //获取客户端输入流
      BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
      //连接客户端输出流
      PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
      out.print("欢迎来聊天室");
      //如果没有断开连接
      while (!isServiceDestoryed) {
       //读取下一行
       String str = in.readLine();
       Log.d(TAG, "msg from client:" + str);
       if (str == null) {
           break;
       }
       //随机获取一个回复的短语
       int i = new Random().nextInt(definedMessages.length);
       String msg = definedMessages[i];
       //在客户端输出
       out.println(msg);
       Log.d(TAG, "send:" + msg);
      }
      Log.d(TAG, "client quit");
      MyUtils.close(out);
      MyUtils.close(in);
      client.close();

      最后记得连接断开后关闭对应的流。

总结

我们现在基本上都离不开互联网了,而网络之中浏览器与web通讯,QQ聊天等常见的通讯都离不开socket,所以即使作为客户端开发人员,了解一些socket知识也是十分必要的,希望这篇文章能够帮助大家对Socket有一个简单直观的了解。


相关文章:

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一共包括10个以上的聊天程序版本!绝对物有所值! 为感谢大家长期的支持,我将下载所需的资源分下调为2。网络聊天程序设计(可选)  实验要求 1、分析典型网络聊天应用软件(如QQ、MSN等)的实现原理,模拟设计一套网络聊天应用程序,必须实现以下功能: ①按照C/S结构分别设计服务端程序和客户端程序; ②服务端通过图形用户界面实现对服务器的控制,负责维护用户帐户和用户群,并维护用户信息、维持客户端之间的端对端通信和群聊通信、适时维护用户在线信息,并能够发送广播消息。 2、增加尽可能多的功能,用户界面友好,操作简便,代码设计遵从程序设计规范,易读性强,对关键过程和代码进行标注说明。 3、程序设计过程遵从软件工程规范,有需求分析、系统设计和详细设计过程,有相应的规范化说明文档。  实验提示 1、客户端之间的通信是通过服务器进行转发的,对于两个客户端,服务器需要创建两个套接字分别维持与客户端之间的连接。当客户端需要向另一个客户发送消息时,它首先将消息发送到服务器,由服务器根据目标用户帐户转发到目标主机。 2、群聊是采用多播技术实现的,也可以采用单播技术实现,但是服务器开销会增加。具体说来,若采用组播技术,当服务端收到来自一个客户端的消息后,向预先分配的该组组播地址转发该消息。若采用单播技术,服务端需要向该组内的所有客户端一一转发该消息。 3、广播消息通过广播方式发送由服务端创建的消息。 4、服务端根据客户的连接和断开情况,实时向其它客户端发送用户在线信息。 实验题目二:自选网络通信程序设计(可选)  实验要求 可以自选与网络通信相关的设计题目,要求如下: 1、在确定实验题目、设计内容以及设计功能指标要求后,向实验指导教师提交书面申请,由实验指导教师根据所选实验题目的难度和工作量确定立题后方能开始实验。 2、选择的实验题目必须具有一定综合性,并能够利用网络通信原理加以解决,同时需要具备一定的工作量。 3、设计的结果要求用户界面友好,操作简便,代码设计遵从程序设计规范,易读性强,对关键过程和代码进行标注说明。 4、程序设计过程遵从软件工程规范,有需求分析、系统设计和详细设计过程,有相应的规范化说明文档。 5、严禁抄袭别人成果,但可以部分借鉴。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值