热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要介绍了详解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 mList = new ArrayList();
 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 

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

布局文件:activity_main.xml:



 
 
 
 

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();
 }
}

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


推荐阅读
  • PyQt5 QTextEdit:深入解析Python中多功能GUI库的应用与实现
    本文详细探讨了 PyQt5 中 QTextEdit 组件在 Python 多功能 GUI 库中的应用与实现。PyQt5 是 Qt 框架的 Python 绑定,提供了超过 620 个类和 6000 个函数及方法,广泛应用于跨平台应用程序开发。QTextEdit 作为其中的重要组件,支持丰富的文本编辑功能,如富文本格式、文本高亮和自定义样式等。PyQt5 的流行性不仅在于其强大的功能,还在于其易用性和灵活性,使其成为开发复杂用户界面的理想选择。 ... [详细]
  • Nmap端口检测与网络安全性评估
    Nmap 是一款强大的网络扫描工具,能够高效地进行主机发现、端口扫描和服务识别。它不仅能够检测网络中活跃的主机,还能详细列出这些主机上开放的端口及其对应的服务和版本信息。此外,Nmap 还具备操作系统指纹识别和硬件地址探测功能,为网络安全评估提供了全面的数据支持。 ... [详细]
  • 华为捐赠欧拉操作系统,承诺不推商用版
    华为近日宣布将欧拉开源操作系统捐赠给开放原子开源基金会,并承诺不会推出欧拉的商用发行版。此举旨在推动欧拉和鸿蒙操作系统的全场景融合与生态发展。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 在使用Eclipse进行调试时,如果遇到未解析的断点(unresolved breakpoint)并显示“未加载符号表,请使用‘file’命令加载目标文件以进行调试”的错误提示,这通常是因为调试器未能正确加载符号表。解决此问题的方法是通过GDB的`file`命令手动加载目标文件,以便调试器能够识别和解析断点。具体操作为在GDB命令行中输入 `(gdb) file `。这一步骤确保了调试环境能够正确访问和解析程序中的符号信息,从而实现有效的调试。 ... [详细]
  • 基于JSP和SSM框架的超市收银系统毕业设计论文及源代码分析
    本研究基于JSP和SSM框架开发了一套超市收银系统,旨在提升超市收银效率和管理便捷性。系统运行环境包括JDK 1.8、Tomcat 7.0、MySQL数据库以及HBuilderX(也可使用WebStorm)作为前端开发工具,后端开发则采用Eclipse(IntelliJ IDEA亦可)。该系统实现了商品管理、订单处理、库存管理和报表生成等核心功能,具有良好的稳定性和扩展性。通过详细的设计与实现过程,本文为相关领域的研究提供了有价值的参考。 ... [详细]
  • 深入理解Linux网络编程:UDP协议实战解析
    深入理解Linux网络编程:UDP协议实战解析 ... [详细]
  • 本文探讨了文件传输过程中的优化与安全策略。具体而言,研究了如何将客户端的文件高效上传至服务器。通过使用结构体对象,可以封装文件的相关信息,如位置和大小,并利用缓冲区存储实际数据,从而实现高效的数据传输。此外,文章还讨论了在传输过程中确保数据完整性和安全性的多种方法,包括加密技术和身份验证机制。 ... [详细]
  • C#中实现高效UDP数据传输技术
    C#中实现高效UDP数据传输技术 ... [详细]
  • 西北工业大学作为陕西省三所985和211高校之一,虽然在农业和林业领域不如某些顶尖院校,但在航空航天领域的实力尤为突出。该校的计算机科学专业在科研和教学方面也具有显著优势,是考研的理想选择。 ... [详细]
  • SQL Server 2008 默认使用1433端口进行通信,但有时会误认为是5432端口,后者实际上已被IANA(互联网号码分配机构)指定为PostgreSQL的默认端口。本文详细解析了SQL Server 2008的端口配置,并提供了增强安全性的配置建议,包括更改默认端口、启用防火墙规则和实施严格的访问控制策略,以减少潜在的安全风险。 ... [详细]
  • 如何使用专业软件打开和编辑PHP电影文件?
    如何使用专业软件打开和编辑PHP电影文件? ... [详细]
  • DNS解析流程详解
    在网络通信中,大多数数据交换依赖于TCP/IP协议,该协议以IP地址为基础。因此,计算机在互联网上进行通信时,主要通过如“202.96.134.133”这样的IP地址来识别目标设备。然而,为了提高用户体验和便于记忆,DNS(域名系统)应运而生,将易于理解的域名转换为IP地址,确保高效且准确的网络连接。本文详细解析了DNS解析的整个流程,包括域名查询、缓存机制及递归解析等关键环节,帮助读者深入了解这一核心网络技术。 ... [详细]
  • 端口转发(Port Forwarding)类似于服务重定向,许多路由器中也称其为虚拟服务器(Virtual Server)。通过合理配置端口转发,可以实现外部网络对内部网络中特定设备和服务的高效访问,从而提高通信效率和灵活性。此外,正确设置端口转发还能增强网络安全,确保只有授权的流量能够进入内网,有效防止未授权访问和潜在威胁。 ... [详细]
  • ——pun的配置,以及实现头盔以及两个手柄的同步。下载完pun并导入后如图所示有这些东西,pun的介绍还是很清楚的,有很多demo可以学习,而且文档自带。很容易上手。首先,就是服务器的配置了。 ... [详细]
author-avatar
冰weiter
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有