详解Android 基于TCP和UDP协议的Socket通信

本来想讲一下基础的网络通信方面的知识点,发现太枯燥乏味了,不过笔试中也经常会问到这方面的问题,所以关于通信方面的知识点,小编会放到面试中去,因为实战中也就面试会用到这方面知识点

Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信。两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。

而Socket通信中基于TCP/IP协议的通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求。而UDP则是提供无连接的数据报服务,UDP在发送数据报前不需建立连接,不对数据报进行检查即可发送数据包

1.什么是Socket?

2.Socket通信模型:

Socket通信实现步骤解析:

Step 1:创建ServerSocket和Socket

Step 2:打开连接到的Socket的输入/输出流

Step 3:按照协议对Socket进行读/写操作

Step 4:关闭输入输出流,以及Socket

好的,我们接下来写一个简单的例子,开启服务端后,客户端点击按钮然后链接服务端, 并向服务端发送一串字符串,表示通过Socket链接上服务器~

一、1.基于TCPSocket服务端的编写:

服务端要做的事有这些:

Step 1 :创建ServerSocket对象,绑定监听的端口

Step 2 :调用accept()方法监听客户端的请求

Step 3 :连接建立后,通过输入流读取客户端发送的请求信息

Step 4 :通过输出流向客户端发送响应信息 Step 5 :关闭相关资源

代码实现:

创建一个Java项目,然后把Java代码贴进去即可!这里可以用eclipse来写服务端,as来写安卓端

public class SocketServer {
 public static void main(String[] args) throws IOException {
  //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
  ServerSocket serverSocket = new ServerSocket(12345);
  InetAddress address = InetAddress.getLocalHost();
  String ip = address.getHostAddress();
  Socket socket = null;
  //2.调用accept()等待客户端连接
  System.out.println("~~~服务端已就绪,等待客户端接入~,服务端ip地址: " + ip);
  socket = serverSocket.accept();
  //3.连接后获取输入流,读取客户端信息
  InputStream is=null;
  InputStreamReader isr=null;
  BufferedReader br=null;
  OutputStream os=null;
  PrintWriter pw=null;
  is = socket.getInputStream();  //获取输入流
  isr = new InputStreamReader(is,"UTF-8");
  br = new BufferedReader(isr);
  String info = null;
  while((info=br.readLine())!=null){//循环读取客户端的信息
   System.out.println("客户端发送过来的信息" + info);
  }
  socket.shutdownInput();//关闭输入流
  socket.close();
 }
}

然后我们把代码run起来,控制台会打印:

好的,接下来到Android客户端了!

2.Socket客户端的编写: 客户端要做的事有这些:

Step 1 :创建Socket对象,指明需要链接的服务器的地址和端号

Step 2 :链接建立后,通过输出流向服务器发送请求信息

Step 3 :通过输出流获取服务器响应的信息

Step 4 :关闭相关资源

代码实现:

MainActivity.java:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  Button btn_accept = (Button) findViewById(R.id.btn_accept);
  btn_accept.setOnClickListener(this);
 }

 @Override
 public void onClick(View v) {
  new Thread() {
   @Override
   public void run() {
    try {
     acceptServer();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }.start();
 }

 private void acceptServer() throws IOException {
  //1.创建客户端Socket,指定服务器地址和端口
  Socket socket = new Socket("172.16.2.54", 12345);
  //2.获取输出流,向服务器端发送信息
  OutputStream os = socket.getOutputStream();//字节输出流
  PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
  //获取客户端的IP地址
  InetAddress address = InetAddress.getLocalHost();
  String ip = address.getHostAddress();
  pw.write("客户端:~" + ip + "~ 接入服务器!!");
  pw.flush();
  socket.shutdownOutput();//关闭输出流
  socket.close();
 }
}

因为Android不允许在主线程(UI线程)中做网络操作,所以这里需要我们自己 另开一个线程来连接Socket!

运行结果:

点击按钮后,服务端控制台打印:

3.简易聊天室

那么通过上面的案例,我们就可以做一个简单的聊天软件,这里知道怎么实现的就可以了,实战中我们都是采用的第三方API,比如网易云,我会专门写一个网易云的IM通信

实现的效果图:

先把我们的服务端跑起来:

接着把我们的程序分别跑到两台模拟器上:

接下来我们来写代码:

首先是服务端,就是将读写socket的操作放到自定义线程当中,创建ServerSocket后,循环 调用accept方法,当有新客户端接入,将socket加入集合当中,同时在线程池新建一个线程!

另外,在读取信息的方法中,对输入字符串进行判断,如果为bye字符串,将socket从集合中 移除,然后close掉!

public class Server {
 //定义相关的参数,端口,存储Socket连接的集合,ServerSocket对象
 //以及线程池
 private static final int PORT = 12345;
 private List<Socket> mList = new ArrayList<Socket>();
 private ServerSocket server = null;
 private ExecutorService myExecutorService = null;

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

 public Server()
 {
  try
  {
   server = new ServerSocket(PORT);
   //创建线程池
   myExecutorService = Executors.newCachedThreadPool();
   System.out.println("服务端运行中...\n");
   Socket client = null;
   while(true)
   {
    client = server.accept();
    mList.add(client);
    myExecutorService.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)
     {
      if(msg.equals("bye"))
      {
       System.out.println("~~~~~~~~~~~~~");
       mList.remove(socket);
       in.close();
       msg = "用户:" + socket.getInetAddress()
         + "退出:" +"当前在线人数:"+mList.size();
       socket.close();
       this.sendmsg();
       break;
      }else{
       msg = socket.getInetAddress() + " 说: " + msg;
       this.sendmsg();
      }
     }
    }
   }catch(Exception e){e.printStackTrace();}
  }

  //为连接上服务端的每个客户端发送信息
  public void sendmsg()
  {
   System.out.println(msg);
   int num = mList.size();
   for(int index = 0;index < num;index++)
   {
    Socket mSocket = mList.get(index);
    PrintWriter pout = null;
    try {
     pout = new PrintWriter(new BufferedWriter(
       new OutputStreamWriter(mSocket.getOutputStream(),"UTF-8")),true);
     pout.println(msg);
    }catch (IOException e) {e.printStackTrace();}
   }
  }

 }
}

接着到客户端,客户端的难点在于要另外开辟线程的问题,因为Android不允许直接在 主线程中做网络操作,而且不允许在主线程外的线程操作UI,这里的做法是自己新建 一个线程,以及通过Hanlder来更新UI,实际开发不建议直接这样做!!!

布局文件:activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

 <TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="小猪简易聊天室" />
 <TextView
  android:id="@+id/txtshow"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  />
 <EditText
  android:id="@+id/editsend"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  />
 <Button
  android:id="@+id/btnsend"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="发送"
  />
</LinearLayout>

MainActivity.java:

public class MainActivity extends AppCompatActivity implements Runnable {

 //定义相关变量,完成初始化
 private TextView txtshow;
 private EditText editsend;
 private Button btnsend;
 private static final String HOST = "172.16.2.54";
 private static final int PORT = 12345;
 private Socket socket = null;
 private BufferedReader in = null;
 private PrintWriter out = null;
 private String content = "";
 private StringBuilder sb = null;

 //定义一个handler对象,用来刷新界面
 public Handler handler = new Handler() {
  public void handleMessage(Message msg) {
   if (msg.what == 0x123) {
    sb.append(content);
    txtshow.setText(sb.toString());
   }
  }

  ;
 };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  sb = new StringBuilder();
  txtshow = (TextView) findViewById(R.id.txtshow);
  editsend = (EditText) findViewById(R.id.editsend);
  btnsend = (Button) findViewById(R.id.btnsend);

  //当程序一开始运行的时候就实例化Socket对象,与服务端进行连接,获取输入输出流
  //因为4.0以后不能再主线程中进行网络操作,所以需要另外开辟一个线程
  new Thread() {

   public void run() {
    try {
     socket = new Socket(HOST, PORT);
     in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
     out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
       socket.getOutputStream())), true);
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }.start();

  //为发送按钮设置点击事件
  btnsend.setOnClickListener(new View.OnClickListener() {

   @Override
   public void onClick(View v) {
    String msg = editsend.getText().toString();
    if (socket.isConnected()) {
     if (!socket.isOutputShutdown()) {
      out.println(msg);
     }
    }
   }
  });
  new Thread(MainActivity.this).start();
 }

 //重写run方法,在该方法中输入流的读取
 @Override
 public void run() {
  try {
   while (true) {
    if (socket.isConnected()) {
     if (!socket.isInputShutdown()) {
      if ((content = in.readLine()) != null) {
       content += "\n";
       handler.sendEmptyMessage(0x123);
      }
     }
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

二、基于UDP协议的Socket通信

TCP和UDP最大的区别在于是否需要客户端与服务端建立连接后才能进行 数据传输,

TCP:传输前先开服务端,accept,等客户端接入,然后获得 客户端socket然后进行IO操作,而UDP则不用

UDP:以数据报作为数据的传输载体,在进行传输时 首先要把传输的数据定义成数据报(Datagram),在数据报中指明数据要到达的Socket(主机地址 和端口号),然后再将数据以数据报的形式发送出去

1.服务端实现步骤:

Step 1:创建DatagramSocket,指定端口号

Step 2:创建DatagramPacket

Step 3:接收客户端发送的数据信息

Step 4:读取数据

示例代码:

public class UPDServer {
 public static void main(String[] args) throws IOException {
  /*
   * 接收客户端发送的数据
   */
  // 1.创建服务器端DatagramSocket,指定端口
  DatagramSocket socket = new DatagramSocket(12345);
  // 2.创建数据报,用于接收客户端发送的数据
  byte[] data = new byte[1024];// 创建字节数组,指定接收的数据包的大小
  DatagramPacket packet = new DatagramPacket(data, data.length);
  // 3.接收客户端发送的数据
  System.out.println("****服务器端已经启动,等待客户端发送数据");
  socket.receive(packet);// 此方法在接收到数据报之前会一直阻塞
  // 4.读取数据
  String info = new String(data, 0, packet.getLength());
  System.out.println("我是服务器,客户端说:" + info);

  /*
   * 向客户端响应数据
   */
  // 1.定义客户端的地址、端口号、数据
  InetAddress address = packet.getAddress();
  int port = packet.getPort();
  byte[] data2 = "欢迎您!".getBytes();
  // 2.创建数据报,包含响应的数据信息
  DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
  // 3.响应客户端
  socket.send(packet2);
  // 4.关闭资源
  socket.close();
 }
}

2.客户端实现步骤:

Step 1:定义发送信息

Step 2:创建DatagramPacket,包含将要发送的信息

Step 3:创建DatagramSocket

Step 4:发送数据

public class UDPClient {
 public static void main(String[] args) throws IOException {
  /*
   * 向服务器端发送数据
   */
  // 1.定义服务器的地址、端口号、数据
  InetAddress address = InetAddress.getByName("localhost");
  int port = 8800;
  byte[] data = "用户名:admin;密码:123".getBytes();
  // 2.创建数据报,包含发送的数据信息
  DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
  // 3.创建DatagramSocket对象
  DatagramSocket socket = new DatagramSocket();
  // 4.向服务器端发送数据报
  socket.send(packet);

  /*
   * 接收服务器端响应的数据
   */
  // 1.创建数据报,用于接收服务器端响应的数据
  byte[] data2 = new byte[1024];
  DatagramPacket packet2 = new DatagramPacket(data2, data2.length);
  // 2.接收服务器响应的数据
  socket.receive(packet2);
  // 3.读取数据
  String reply = new String(data2, 0, packet2.getLength());
  System.out.println("我是客户端,服务器说:" + reply);
  // 4.关闭资源
  socket.close();
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Android使用WebSocket实现多人游戏
  • 详解OkSocket与Android的简单使用
  • Android开发之Socket通信传输简单示例
  • android基于socket的局域网内服务器与客户端加密通信
  • android socket聊天室功能实现
  • SpringBoot webSocket实现发送广播、点对点消息和Android接收
  • Android中Socket大文件断点上传示例
  • android Socket实现简单聊天功能以及文件传输
  • 详解Android使用Socket对大文件进行加密传输
  • 详解Android 通过Socket 和服务器通讯(附demo)
  • Android Socket接口实现即时通讯实例代码
  • Android完整Socket解决方案
(0)

相关推荐

  • SpringBoot webSocket实现发送广播、点对点消息和Android接收

    1.SpringBoot webSocket SpringBoot 使用的websocket 协议,不是标准的websocket协议,使用的是名称叫做STOMP的协议. 1.1 STOMP协议说明 STOMP,Streaming Text Orientated Message Protocol,是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议. 它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消

  • 详解OkSocket与Android的简单使用

    一个Android轻量级Socket通讯框架,既OkHttp后又一力作. 框架开源地址: https://github.com/xuuhaoo/OkSocket,欢迎star,fork,Issue交流 OkSocket简介 Android OkSocket是一款基于阻塞式传统Socket的一款Socket客户端整体解决方案.您可以使用它进行简单的基于Tcp协议的Socket通讯,当然,也可以进行大数据量复杂的Socket通讯, 支持单工,双工通讯. Maven配置 OkSocket 目前仅支持

  • Android完整Socket解决方案

    整体步骤流程 先来说一下整体的步骤思路吧: 发送 UDP 广播,大家都知道 UDP 广播的特性是整个网段的设备都可以收到这个消息. 接收方收到了 UDP 的广播,将自己的 ip 地址,和双方约定的端口号,回复给 UDP 的发送方. 发送方拿到了对方的 ip 地址以及端口号,就可以发起 TCP 请求了,建立 TCP 连接. 保持一个 TCP 心跳,如果发现对方不在了,超时重复 1 步骤,重新建立联系. 整体的步骤就和上述的一样,下面用代码展开: 搭建 UDP 模块 public UDPSocket

  • Android Socket接口实现即时通讯实例代码

    Android Socket接口实现即时通讯 最近学习Android 通信的知识,做一个小实例,巩固下学习内容,以下内容是网上找的资料,觉得很不错,知识比较全面,大家看下. 首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.

  • 详解Android 通过Socket 和服务器通讯(附demo)

    Android 通过Socket 和服务器通讯,是一种比较常用的通讯方式,时间比较紧,说下大致的思路,希望能帮到使用socket 进行通信的人 (1)开启一个线程发送消息    SocketOutputThread 消息是放在队列里的,当有消息后,进入队列,线程唤醒,发送消息,并反馈发送是否成功的回调 (2)开启一个线程接受服务器消息 SocketInputThread 为了防止一直收数据,浪费电池的电,采用NIO的方式读socket的数据,这个是本文的关键 (3)开启一个线程,做心跳,防止so

  • Android开发之Socket通信传输简单示例

    本文实例讲述了Android Socket通信传输实现方法.分享给大家供大家参考,具体如下: 1.开篇简介 Socket本质上就是Java封装了传输层上的TCP协议(注:UDP用的是DatagramSocket类).要实现Socket的传输,需要构建客户端和服务器端.另外,传输的数据可以是字符串和字节.字符串传输主要用于简单的应用,比较复杂的应用(比如Java和C++进行通信),往往需要构建自己的应用层规则(类似于应用层协议),并用字节来传输. 2.基于字符串传输的Socket案例 1)服务器端

  • android基于socket的局域网内服务器与客户端加密通信

    实现了基本的socket通信(即两台设备,一台用作服务器,一台用作客户端),服务器进行监听,客户端发送加密数据到服务器,服务器进行解密得到明文. 注意:本项目中使用了ButterKnife及EventBus作为辅助工具,通信建立时默认网络正常(未做局域网网络环境检测),加密方式为AES加密 1.效果图: (1)客户端 (2)服务器端 2.界面布局部分 (1)服务器端布局 function_socket_server.xml <?xml version="1.0" encoding

  • 详解Android使用Socket对大文件进行加密传输

    前言 数据加密,是一门历史悠久的技术,指通过加密算法和加密密钥将明文转变为密文,而解密则是通过解密算法和解密密钥将密文恢复为明文.它的核心是密码学. 数据加密目前仍是计算机系统对信息进行保护的一种最可靠的办法.它利用密码技术对信息进行加密,实现信息隐蔽从而起到保护信息的安全的作用. 项目中使用Socket进行文件传输过程时,需要先进行加密.实现的过程中踏了一些坑,下面对实现过程进行一下总结. DES加密 由于加密过程中使用的是DES加密算法,下面贴一下DES加密代码: //秘钥算法 privat

  • Android使用WebSocket实现多人游戏

    WebSocket 是 HTML5 一种新的协议.它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是: WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样: WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能

  • android Socket实现简单聊天功能以及文件传输

    干程序是一件枯燥重复的事,每当感到内心浮躁的时候,我就会找小说来看.我从小就喜爱看武侠小说,一直有着武侠梦.从金庸,古龙,梁羽生系列到凤歌(昆仑),孙晓(英雄志)以及萧鼎的(诛仙)让我领略着不一样的江湖. 如果你有好看的武侠系列小说,给我留言哦.题外话就扯这么多了,接着还是上技术. 看看今天实现的功能效果图: 可以这里使用多台手机进行通讯,我采用的服务器发送消息. 是不是只有发送消息,有些显得太单调了.好,在发送消息的基础上增加文件传输.后期会增加视频,音频的传输,增加表情包.那一起来看看图文消

  • Android中Socket大文件断点上传示例

    什么是Socket?      所谓Socket通常也称作"套接字",用于描述IP地址和端口,是一个通信连的句柄,应用程序通常通过"套接字"向网络发送请求或者应答网络请求,它就是网络通信过程中端点的抽象表示.它主要包括以下两个协议: TCP (Transmission Control Protocol 传输控制协议):传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据.TCP提供超时重

  • android socket聊天室功能实现

    前提概要 笔者很久之前其实就已经学习过了socket,当然也是用socket做过了聊天室,但是觉得此知识点比较一般,并无特别难的技术点,于是也并未深究. 然而近期一个项目中对socket的使用却让笔者感觉socket强大无比,可以实现诸多功能. 个人Socket体验 项目主要有关智能家居,需要实现多台手机同时对灯进行操作(开或者关),主要需要实现以下几点: 1.进入界面时获取所有灯的状态. 2.一台手机改变了灯的状态,其他的手机上可以有所显示. 3.硬件上改变了灯的状态(手动开关灯),所有手机上

随机推荐