Android网络功能开发(6)——TCP协议通信

这篇具有很好参考价值的文章主要介绍了Android网络功能开发(6)——TCP协议通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

TCP通信的双方需要建立连接,所以先由一方监听某个端口,等待其他设备来连接,这一方称为服务器端。另一方向服务器端发起连接请求,称为客户端。服务器端接受客户端的连接请求后,双方之间的连接建立起来。连接建立后,双方对于连接的使用是相同的,都可以通过连接发送和接收数据。

Android网络功能开发(6)——TCP协议通信

如果双方通信时没有像HTTP协议这种一问一答的固定模式,就需要随时接收和处理对方发来的数据,所以要把接收和处理数据的工作在一个单独的线程中执行。如果服务器端想同时与多个客户端通信,要对每个客户端的连接建立一个接收线程。

下面通过一个简单的聊天室原型来演示如何编程实现TCP通信。聊天室系统包含一个服务器和多个客户端。服务器对从一个客户端接收的信息,要转发到所有客户端。客户端要把从服务器接收的信息显示给用户,并把用户输入的信息发送到服务器。为实现这一功能,系统的结构要像下面这个图这样设计。

Android网络功能开发(6)——TCP协议通信

聊天服务器端有一个TCP监听线程,当有客户端发来连接请求时,负责接受客户端的连接请求并创建接收线程。同时,用一个列表记下所有的客户端连接。这样,接收线程就能够将接收到的信息发往列表中保存的所有客户端。客户端也有两个线程,接收线程负责从服务器接收数据并显示给用户,主线程接收用户的输入并发往服务器。

服务器端运行在JavaSE上,的具体代码是这样的:

Android网络功能开发(6)——TCP协议通信

监听线程ListeningThread首先创建一个ServerSocket对象,然后循环调用它的accept方法等待接受客户端的连接请求。当有客户端发来连接请求时,accept方法返回一个Socket对象。监听线程把Socket对象添加到连接列表connections,并创建一个接收线程ServiceThread。

接收线程循环调用readLine,一旦客户端有消息发来,readLine就会返回发来的消息内容,然后调用chatMessage发送到所有客户端(包括自己)。

chatMessage方法遍历客户端列表connections,把客户端发来的消息转发到所有客户端。

客户端是一个Android应用,界面是这样的:最上面一行文本框中输入服务器的IP地址;下面TCP一行的三个按钮控制建立连接、发送信息、断开连接;再下面UDP一行三个按钮用于测试UDP通信方式;再下面的Content文本框是要发送的聊天消息;最下面的文本是所有聊天内容。

Android网络功能开发(6)——TCP协议通信

当点击TCP的Connect按钮时,以服务器端的IP地址和端口号为参数创建一个Socket对象,这样就会向服务器发送一个建立连接的请求。如果服务器接受请求,那么连接就成功建立,Socket对象也会创建成功,否则会产生异常,转入异常处理流程。

有了Socket对象后,接着创建一个接收数据的线程。注意这部分代码也需要用AsyncTask异步执行,不能占用主线程。接收线程中循环调用in.readLine方法不断读取服务器发来的消息,一旦有消息发过来,该方法就会返回消息内容。接着再调用sendMessage把消息内容传给主线程显示,因为子线程中不能直接操作界面控件。

传递消息内容用的Android的Handler机制,主线程中创建一个Handler对象,并在它的handleMessage方法中接收消息。子线程中调用该Handler对象的sendMessage方法传递消息。这样就能在线程间传递消息了。

当点击TCP的Send按钮时,代码是把Content文本框中的字符串通过Socket连接发送到服务器。

Android端的布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="Server:"
        android:textAppearance="?android:attr/textAppearanceLarge"
        app:layout_constraintEnd_toStartOf="@+id/editTextServer"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/editTextServer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        app:layout_constraintBaseline_toBaselineOf="@+id/textView1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView1">

        <requestFocus
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </EditText>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="6dp"
        android:text="TCP: "
        android:textAppearance="?android:attr/textAppearanceLarge"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/buttonTCPConnect" />

    <Button
        android:id="@+id/buttonTCPConnect"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Connect"
        android:textAllCaps="false"
        app:layout_constraintBaseline_toBaselineOf="@+id/buttonTCPSend"
        app:layout_constraintStart_toEndOf="@+id/textView2" />

    <Button
        android:id="@+id/buttonTCPSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginLeft="10dp"
        android:text="Send"
        android:textAllCaps="false"
        app:layout_constraintStart_toStartOf="@+id/buttonUDPSend"
        app:layout_constraintTop_toBottomOf="@+id/editTextServer" />

    <Button
        android:id="@+id/buttonTCPClose"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Close"
        android:textAllCaps="false"
        app:layout_constraintBaseline_toBaselineOf="@+id/buttonTCPSend"
        app:layout_constraintStart_toEndOf="@+id/buttonTCPSend" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="6dp"
        android:text="UDP:"
        android:textAppearance="?android:attr/textAppearanceLarge"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/buttonUDPListen" />

    <Button
        android:id="@+id/buttonUDPListen"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Listen"
        android:textAllCaps="false"
        app:layout_constraintBaseline_toBaselineOf="@+id/buttonUDPSend"
        app:layout_constraintStart_toEndOf="@+id/textView3" />

    <Button
        android:id="@+id/buttonUDPSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send"
        android:textAllCaps="false"
        app:layout_constraintStart_toEndOf="@+id/buttonUDPListen"
        app:layout_constraintTop_toBottomOf="@+id/buttonTCPConnect" />

    <Button
        android:id="@+id/buttonUDPStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Stop"
        android:textAllCaps="false"
        app:layout_constraintBaseline_toBaselineOf="@+id/buttonUDPSend"
        app:layout_constraintStart_toEndOf="@+id/buttonUDPSend" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Content:"
        android:textAppearance="?android:attr/textAppearanceLarge"
        app:layout_constraintBaseline_toBaselineOf="@+id/editTextContent"
        app:layout_constraintStart_toStartOf="parent" />

    <EditText
        android:id="@+id/editTextContent"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView4"
        app:layout_constraintTop_toBottomOf="@+id/buttonUDPListen" />

    <TextView
        android:id="@+id/textViewResult"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editTextContent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Android端的完整代码如下:

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
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 java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class MainActivity extends AppCompatActivity {
    EditText etServer;
    EditText etContent;
    TextView tvResult;

    Handler mHandler;

    Socket tcpSocket;
    TCPReceiveThread tcpReceiveThread;

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

        etServer = findViewById(R.id.editTextServer);
        etContent = findViewById(R.id.editTextContent);
        tvResult = findViewById(R.id.textViewResult);

        etServer.setText("192.168.1.2");

        tcpSocket = null;
        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                switch(msg.what) {
                    case 1:	// receive socket message
                        String received = (String)msg.obj;
                        tvResult.append(received+"\r\n");
                        break;
                }
            }
        };

        Button btnTCPConnect = findViewById(R.id.buttonTCPConnect);
        btnTCPConnect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                String serverIP = etServer.getText().toString();
                // tcpConnect(serverIP);	// 不能在主线程中执行网络操作
                new AsyncTask<String, Void, Void>(){
                    @Override
                    protected Void doInBackground(String... arg0) {
                        try {
                            tcpConnect(arg0[0]);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return null;
                    }
                }.execute(serverIP);
            }
        });

        Button btnTCPSend = findViewById(R.id.buttonTCPSend);
        btnTCPSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                new AsyncTask<String, Void, Void>(){
                    @Override
                    protected Void doInBackground(String... arg0) {
                        try {
                            tcpSend(arg0[0]);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return null;
                    }
                }.execute(etContent.getText().toString());
                etContent.setText("");
            }
        });

        Button btnTCPClose = (Button) findViewById(R.id.buttonTCPClose);
        btnTCPClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                new AsyncTask<Void, Void, Void>(){
                    @Override
                    protected Void doInBackground(Void... arg0) {
                        try {
                            tcpDisconnect();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return null;
                    }
                }.execute();
            }
        });

    }
    void tcpConnect(String ip) throws IOException {
        if(tcpSocket!=null) tcpDisconnect();
        tcpSocket = new Socket(ip, 8899);
        tcpSocket.setSoTimeout(1000);
        tcpReceiveThread = new TCPReceiveThread();
        tcpReceiveThread.start();
    }

    void tcpSend(String ctx) throws IOException {
        ctx += "\r\n";
        byte[] buf = ctx.getBytes("UTF-8");
        tcpSocket.getOutputStream().write(buf);
    }

    void tcpDisconnect() throws IOException {
        if(tcpReceiveThread!=null)
            tcpReceiveThread.setStopFlag();	// 具体的关闭操作在接收线程结束后执行,
    }

    void sendMessage(String str){
        Message msg = Message.obtain();	// 从Message池中取Message对象,用new创建会用到内存分配,影响效率
        msg.what = 1;
        msg.obj = str;
        mHandler.sendMessage(msg);
    }

    class TCPReceiveThread extends Thread {
        private boolean flag;

        public void setStopFlag(){
            flag = false;
        }

        @Override
        public void run(){
            try {
                flag = true;
                BufferedReader in = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream(), "UTF-8"));
                sendMessage("TCP socket connection connected");
                String line = null;
                while(flag) {
                    try {
                        line = in.readLine();
                    } catch (SocketTimeoutException e){
                        //e.printStackTrace();
                        //flag = false;
                    }
                    if(line != null) {
                        System.out.println(line);
                        sendMessage(line);
                        line = null;
                    }
                }
                in.close();
                tcpSocket.close();
                tcpSocket = null;
                sendMessage("TCP socket connection closed");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

Server端在JavaSE平台上实现,完整代码如下:

import java.io.*;
import java.net.*;
import java.util.*;

public class ChatServer {
	public static void main(String[] args){
		Thread listeningThread = new ListeningThread(8899);
		listeningThread.start();
	}
}
class ListeningThread extends Thread {
	private int port;
	private boolean flag = true;
	private ServerSocket lServerSocket;
	private List<PrintWriter> connections = new Vector<PrintWriter>();	//保存所有连结
	public ListeningThread(int aPort){
		port = aPort;
	}
	public void run(){
		try {
			lServerSocket = new ServerSocket(port);
			lServerSocket.setSoTimeout(1000);
			System.out.println("TCP Socket Start listening......");
			while(flag) {
				try {
					Socket incoming = lServerSocket.accept();
					System.out.println("Accept "+incoming.getInetAddress()+"("+incoming.getPort()+")");
					//PrintWriter out = new PrintWriter(incoming.getOutputStream(),true);
					PrintWriter out = new PrintWriter(new OutputStreamWriter(incoming.getOutputStream(), "UTF-8"),true);
					connections.add(out);	//有新连结则将其输出流添加到连结列表中
					out.println("Welcome to "+lServerSocket.getInetAddress()+"("+lServerSocket.getLocalPort()+")");	
					out.flush();
					Thread t = new ServiceThread(incoming);	//启动接收数据线程
					t.start();
				}
				catch(SocketTimeoutException e) {
					if(!flag)break;
				}
			}
			lServerSocket.close();
			System.exit(0);
		}
		catch(IOException e) {
			System.out.println(e);
		}
	}
	public synchronized void chatMessage(String msg) {
		Iterator<PrintWriter> iter = connections.iterator();
		while(iter.hasNext()) {
			try {
				PrintWriter out = iter.next();
				out.println(msg);
				out.flush();
			}
			catch(Exception e) {
				iter.remove();	//如果发送中出现异常,则将连结移除
			}
		}
	}
	class ServiceThread extends Thread {
		private Socket lSocket;
		public ServiceThread(Socket aSocket){
			lSocket = aSocket;
		}
		public void run(){
			try {
				BufferedReader in = new BufferedReader(new InputStreamReader(lSocket.getInputStream(), "UTF-8"));
				String line;
				while(flag){
					line = in.readLine();
					if(line != null){
						System.out.println(line);	// 本地屏幕显示
						chatMessage("Chat:"+line);	// 发送到所有客户端
					}
				}
				lSocket.close();
				System.out.println("Thread stoped.");
			}
			catch(IOException e){
				System.out.println(e);
			}
		}
	}
}

完整代码下载:

 Android网络功能开发-Socket编程接口使用的例子文章来源地址https://www.toymoban.com/news/detail-484135.html

到了这里,关于Android网络功能开发(6)——TCP协议通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java】--网络编程:基于TCP协议的网络通信

    TCP协议(Transmission Control Protocol),即传输控制协议,是一种 面向连接 的, 可靠 的,基于 字节流 的传输层通信协议。数据大小无限制。 建立连接的过程需要 三次握手 。 断开连接的过程需要 四次挥手 。 使用TCP协议的通信双方分别为 客户端 和 服务器端 。 客户端负责向服务

    2024年01月23日
    浏览(29)
  • 【网络编程】网络通信基础——简述TCP/IP协议

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程的一点学习心得,欢迎大家在评论区交流讨论💌 ip地址简单来说就是用来描述网络上一个设备的所在位置。 端

    2024年02月04日
    浏览(25)
  • WebSocket | 基于TCP的全双工通信网络协议

    ​🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,专注于Java领域学习,擅长web应用开发、数据结构和算法,初步涉猎Python人工智能开发和前端开发。 🦅主页:@逐梦苍穹 📕所属专栏:Java EE ✈ 您的一键三连,是我创作的最大动力🌹 WebSocket 是基于 TCP 的一

    2024年02月19日
    浏览(21)
  • 深入理解TCP/IP协议:网络通信的基石

    提示:本系列文章重点学习TCP/IP协议 提示:在这里先对TCP/IP协议做一个概述,以便大家能更好的理解: TCP/IP协议是当今互联网世界中最为重要的网络通信协议之一,它承载了全球范围内数以亿计的设备之间的通信。无论是在个人日常使用的智能手机,还是在企业级的网络架

    2024年04月16日
    浏览(17)
  • 深入理解网络通信和TCP、IP协议-01

    计算机网络是什么? 随着计算机技术发展,计算机的体积和价格都在下降,之前计算机多用于研究机构,现 阶段逐步进入一般的公司用于办公。原来计算机之间传输数据需要通过软盘等第三方存储介 质进行转存,人们需要将数据直接通过通信线路传输,来缩短传输时间,于

    2024年02月16日
    浏览(21)
  • linux【网络编程】TCP协议通信模拟实现、日志函数模拟、守护进程化、TCP协议通信流程、三次握手与四次挥手

    Tcp通信模拟实现与Udp通信模拟实现的区别不大,一个是面向字节流,一个是面向数据报;udp协议下拿到的数据可以直接发送,tcp协议下需要创建链接,用文件描述符完成数据的读写 1.1.1 接口认识 1.1.1.1 listen:监听socket 1.1.1.2 accept:获取连接 通信就用accept返回的文件描述符,

    2024年02月06日
    浏览(22)
  • 【网络】socket——TCP网络通信 | 日志功能 | 守护进程

    🐱作者:一只大喵咪1201 🐱专栏:《网络》 🔥格言: 你只管努力,剩下的交给时间! 上篇文章中本喵介绍了UDP网络通信的socket代码,今天介绍TCP网络通信的socket代码。 和 udp 的网络通信一样, tcp 通信也需要服务器指定端口号,IP地址同样使用 0.0.0.0 ,以便客户端所有对服

    2024年02月16日
    浏览(16)
  • socket套接字通信 TCP传输控制协议/IP网络协议 5.18

    B/S :浏览器和服务器 C/S :客户机和服务器 网络的层次结构和每层所使用协议的集合 网络采用分层管理的方法,将网络的功能划分为不同的模块 OSI模型: 共7种: 数据的封装与传递过程: 网络传输数据大小user data: 6~1460 网络传输中容易发生拆包和粘包,所以接收和发送的字节

    2024年02月05日
    浏览(29)
  • 网络编程day2——基于TCP/IP协议的网络通信

            计算机S                                                 计算机C      创建socket对象                                   创建socket对象      准备通信地址(自己的ip(非公网ip))      准备通信地址                                     (计算

    2024年02月10日
    浏览(28)
  • 【计网】TCP协议安全与风险:深入探讨网络通信的基石

       🍎 个人博客: 个人主页 🏆 个人专栏: Linux ⛳️   功不唐捐,玉汝于成 目录 🌐前言 🔒正文 TCP (Transmission Control Protocol): UDP (User Datagram Protocol): HTTP (Hypertext Transfer Protocol): HTTPS (Hypertext Transfer Protocol Secure): 🌐结语  我的其他博客 TCP(传输控制协议)是计算机网络中最

    2024年03月10日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包