原创 Android之Socket实例

2022-1-7 14:18 1851 21 21 分类: 软件与OS 文集: android studio

    Socket(套接字)是对 TCP/IP 协议的封装和应用,根据底层封装协议的不同,Socket 的类型可以分为流套接字(streamsocket)和数据报套接字(datagramsocket)两种。流套接字将TCP作为端对端协议,提供了一个可信赖的字节流服务;数据报套接字使用 UDP 协议,提供数据打包发送服务,应用程序可以通过它发送最长 64KB 的信息。Socket 的通信模型图如1-1所示。


图1-1 Socket 的通信模型图

通过图1-1可以很容易地看出,使用Socket进行两个应用程序之间的通信时可以选择使用TCP还是UDP作为其底层协议。对比两种方式,就会发现它们各有优劣,TCP 首先连接接收方,然后发送数据,保证成功率,速度相对较慢(相比 HTTP 方式还是非常快的);UDP 把数据打包成数据包,然后直接发送对应的IP 地址,速度快,但是不保证成功率,并且数据大小有限。

一个功能齐全的 Socket,都要包含以下基本结构,其工作过程包含4个基本的步骤∶创建Socket,打开连接到 Socket 的输入/出流,按照一定的协议对 Socket进行读/写操作,关闭 Socket。

Java在java.net包中提供了 Socket 和 ServerSocket 两个类,分别用来表示双向连接的客户端和服务端,是Socket编程的核心类。构造方法很多,一般情况下使用下面两种∶

Socket client = new Socket("127.0.0.1 ",999);

ServerSocket server = new ServerSocket(999);

其中,Socket 类用于实例化一个 Client,参数分别是要访问的IP 地址和端口号,这个端口号要与服务端一致。ServerSocket类用于实例化一个 Server,其中的参数用来设置端口这里的端口不能与"3306""80""8080"等常用端口号冲突。

下面以基于TCP的Socket为例来讲解如何使用Socket。

使用Java Socket创建一个服务端程序,运行在eclipse平台,并运行在PC上,然后在手机上编写客户端程序,在局域网内访问服务端。下面先编写服务端,代码如下:

package socket;
  • import java.io.BufferedReader;
  • import java.io.IOException;
  • import java.io.InputStream;
  • import java.io.InputStreamReader;
  • import java.io.OutputStream;
  • import java.net.ServerSocket;
  • import java.net.Socket;
  • public class sockettest {
  • public static void main(String[] args) throws IOException {
  • @SuppressWarnings("resource")
  • ServerSocket service = new ServerSocket(2226);
  • while (true) {
  • //等待客户端连接
  • Socket socket = service.accept();
  • new Thread(new AndroidRunable(socket)).start();
  • }
  • }
  • }
  • class AndroidRunable implements Runnable{
  • Socket socket=null;
  • public AndroidRunable(Socket socket)
  • {
  • this.socket=socket;
  • }
  • public void run(){
  • //向Android客户端输出hello this is www.bigbirdic.com!
  • String line=null;
  • InputStream inputStream;
  • OutputStream outputStream;
  • String str="hello this is www.bigbirdic.com!";
  • try{
  • //向客户端发送信息
  • outputStream=socket.getOutputStream();
  • inputStream=socket.getInputStream();
  • BufferedReader bfr=new BufferedReader(new InputStreamReader(inputStream));
  • outputStream.write(str.getBytes("gbk"));
  • outputStream.flush();
  • //半关闭Socket
  • socket.shutdownOutput();
  • //获取客户端的信息
  • while ((line=bfr.readLine())!=null){
  • System.out.print(line);
  • }
  • //关闭输入输出流
  • outputStream.close();
  • bfr.close();
  • inputStream.close();
  • socket.close();
  • }catch (IOException e)
  • {
  • e.printStackTrace();
  • }
  • }
  • }
  • 复制代码

      这里的代码很简单,单纯地使用ServerSocket建立服务,设置端口号为2226,然后每当有客户端访问时就返回一个“hello this is www.bigbirdic.com!”。编辑完成服务端之后,我们在Android Studio中创建一个用于创建Socket客户端的类,代码如下:

    package com.rfstar.sockettest;
  • import android.util.Log;
  • import java.io.BufferedReader;
  • import java.io.IOException;
  • import java.io.InputStreamReader;
  • import java.io.OutputStream;
  • import java.net.InetSocketAddress;
  • import java.net.Socket;
  • import java.net.SocketException;
  • public class SocketUtil {
  • private String str;
  • private Socket socket;
  • private String ip;
  • public SocketUtil(String str,String ip){
  • this.str=str;
  • this.ip=ip;
  • }
  • public String sendMessage(){
  • String result="";
  • try{
  • socket=new Socket();
  • //ip为电脑所在的局域网网址
  • socket.connect(new InetSocketAddress(ip,2226),5000);
  • OutputStream outputStream=socket.getOutputStream();
  • outputStream.write(str.getBytes());
  • outputStream.flush();
  • BufferedReader bfr=new BufferedReader(new InputStreamReader(socket.getInputStream()));
  • String line=null;
  • StringBuffer buffer=new StringBuffer();
  • while ((line=bfr.readLine())!=null)
  • {
  • buffer.append(line);
  • }
  • result=buffer.toString();
  • bfr.close();
  • outputStream.close();
  • socket.close();
  • }catch (SocketException e)
  • {
  • //连接超时,在UI界面显示消息
  • Log.i("socket",e.toString());
  • }catch (IOException e)
  • {
  • e.printStackTrace();
  • }
  • return result;
  • }
  • }
  • 复制代码

      在本类中,使用Socket连接服务器端,然后发送相关信息并接收服务端数据。代码并不难,下面就在MainActivity中使用此类。当然,使用它之前要先修改MainActivity的布局文件activity_main.xml,代码如下:

    <?xml version="1.0" encoding="utf-8"?>
  • <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  • xmlns:app="http://schemas.android.com/apk/res-auto"
  • xmlns:tools="http://schemas.android.com/tools"
  • android:layout_width="match_parent"
  • android:layout_height="match_parent"
  • android:orientation="vertical"
  • tools:context=".MainActivity">
  • <EditText
  • android:id="@+id/message"
  • android:layout_width="match_parent"
  • android:layout_height="wrap_content"
  • android:paddingTop="50dp"
  • android:textSize="24sp"/>
  • <Button
  • android:id="@+id/button"
  • android:layout_width="match_parent"
  • android:layout_height="wrap_content"
  • android:layout_marginTop="30dp"
  • android:text="发送消息"
  • android:textSize="20dp"/>
  • <TextView
  • android:id="@+id/content"
  • android:layout_width="match_parent"
  • android:layout_height="wrap_content"
  • android:layout_marginTop="30dp"
  • />
  • </LinearLayout>
  • 复制代码

    这里使用一个EditText来编辑向服务端发送的内容,并用一个Button来点击触发网络通信的事件,然后用一个TextView展示服务端返回的值。接下来在MainActivity中通过findViewById()方法来获取这些控件,并设置Button的点击事件,代码如下:

    package com.rfstar.sockettest;
  • import androidx.appcompat.app.AppCompatActivity;
  • import android.os.Bundle;
  • import android.os.Handler;
  • import android.os.Message;
  • import android.view.View;
  • import android.widget.Button;
  • import android.widget.EditText;
  • import android.widget.TextView;
  • import org.w3c.dom.EntityReference;
  • public class MainActivity extends AppCompatActivity {
  • private Button button;
  • private TextView textView;
  • private String result;
  • private Handler handler=new Handler(){
  • @Override
  • public void handleMessage(Message msg){
  • super.handleMessage(msg);
  • if(msg.what==123)
  • {
  • textView.setText(result);
  • }
  • }
  • };
  • @Override
  • protected void onCreate(Bundle savedInstanceState) {
  • super.onCreate(savedInstanceState);
  • setContentView(R.layout.activity_main);
  • initView();
  • }
  • private void initView()
  • {
  • textView=(TextView)findViewById(R.id.content);
  • final EditText editText=(EditText)findViewById(R.id.message);
  • button=(Button)findViewById(R.id.button);
  • button.setOnClickListener(new View.OnClickListener() {
  • @Override
  • public void onClick(View v) {
  • new Thread(new Runnable() {
  • @Override
  • public void run() {
  • result=new SocketUtil(editText.getText().toString(),"192.168.110.82").sendMessage();
  • handler.sendEmptyMessage(123);
  • }
  • }).start();
  • }
  • });
  • }
  • }
  • 复制代码

    至此,实例代码完成,不要忘了还要在AndroidManifest.xml中申请权限:

    <uses-permission android:name="android.permission.INTERNET"/>
    复制代码

      Activity中只是对点击事件做了处理,并将服务端返回的值展示在TextView上。添加完网络权限之后,运行程序,在EditText中输入内容,然后点击“发送消息”按钮,将“hello”发送到服务端,并接收到服务端返回的“hello this is www.bigbirdic.com!”,如图1-2所示。

    观察服务端代码所在的控制台,发现也确实接收到了手机发送的内容,如图1-3所示。

    1-2 Socket的通信:客户端发送并接收响应的消息

    1-3 Socket通信:服务端接收到消息

    android studio工具及手机模拟器以及更多工程源代码下载请前往微信公众号:大鸟科创空间,回复:android studio即可获取。

    作者: 大鸟科创空间, 来源:面包板社区

    链接: https://mbb.eet-china.com/blog/uid-me-3949041.html

    版权声明:本文为博主原创,未经本人允许,禁止转载!

    PARTNER CONTENT

    文章评论0条评论)

    登录后参与讨论
    我要评论
    0
    21
    关闭 站长推荐上一条 /3 下一条