在前一个教程的基础上做了改进,还不错

1、创建项目

2、 布局文件

(1) 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity"
    >
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        &gt;
 
        <EditText
            android:id="@+id/ed_client_ip"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:hint="IP"
            android:text="127.0.0.1"
            android:textSize="14sp"
            />
 
        <EditText
            android:id="@+id/ed_client_port"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="端口"
            android:text="8801"
            android:textSize="14sp"
            />
 
        <Button
            android:id="@+id/btn_start_client"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_margin="0dp"
            android:padding="0dp"
            android:text="连接服务"
            android:textSize="14sp"
            android:onClick="connectServer"
            />
    </LinearLayout>
 
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        >
 
        <EditText
            android:id="@+id/ed_client_send_message"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="发送消息"
            android:text="from client"
            android:textSize="14sp"
            />
 
        <Button
            android:id="@+id/btn_client_send"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_margin="0dp"
            android:padding="0dp"
            android:text="发送消息"
            android:textSize="14sp"
            android:onClick="SendMsgToServer"
            />
    </LinearLayout>
 
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
 
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:text="客户端日志:"
            android:textSize="14sp"
            />
 
        <Button
            android:id="@+id/btn_client_clear_message"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_margin="0dp"
            android:padding="0dp"
            android:text="清除日志"
            android:textSize="14sp"
            android:onClick="clearLog"
            />
    </RelativeLayout>
 
    <ListView
        android:id="@+id/lv_client_msg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
</LinearLayout>

(2)


<?xml version="1.0" encoding="utf-8"?>
 
<TextView
    android:id="@+id/item_log"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="Item Log goes here"
    android:textSize="12sp"
    />

(3)dimens.xml,看起来专业

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>

 3、主程序,注意分成2个了

 (1)

package com.example.chentcpclientsenior;

import androidx.appcompat.app.AppCompatActivity;

import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Looper;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;

import java.io.BufferedReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    TcpClient tcpClient=new TcpClient();
    OnTcpClientConnectListener onTcpClientConnectListener = new OnTcpClientConnectListener();

    private static final String TAG = "chenTcpSenior";

    EditText mEdClientIp;
    EditText mEdClientPort;
    EditText mEdClientSendMessage;
    ListView mLvClientMsg;

    private String mClientIp;
    private int mClientPort;
    private Socket mClientSocket;
    private BufferedReader mClientIn;
    private PrintWriter mClientOut;
    private String mClientSendMessage;
    Button btn_start_client;

    private List<String> mClientMessageList;
    private ArrayAdapter<String> mClientMessageAdapter;

    private boolean connectFlag = false;  //是否连接标记,如果已连接就不新创建连接
//    private Object OnTcpClientConnectListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //android.os.NetworkOnMainThreadException
        //简单暴力,强制使用代码修改简单(但是非常不推荐)
        if (android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }

        initView();
        initData();
    }
    private void initView() {
        mEdClientIp = findViewById(R.id.ed_client_ip);
        mEdClientPort = findViewById(R.id.ed_client_port);
        mEdClientSendMessage = findViewById(R.id.ed_client_send_message);
        mLvClientMsg = findViewById(R.id.lv_client_msg);

        btn_start_client = findViewById(R.id.btn_start_client);
    }
    private void initData() {
        String serverIp = getLocalIpAddress();
        Log.e(TAG, "initData serverIp=" + serverIp);
        mEdClientIp.setText(serverIp);
        mClientMessageList = new ArrayList<>();
        mClientMessageAdapter = new ArrayAdapter<>(this, R.layout.item_log, R.id.item_log, mClientMessageList);
        mLvClientMsg.setAdapter(mClientMessageAdapter);
    }

    //以太网消息处理接口实现
    public class OnTcpClientConnectListener implements TcpClient.OnConnectListener{
        public void onConnectSuccess(String inetAddress, String localAddress)
        {
            Log.e(TAG, "onConnectSuccess");
            logClient(getTime() +"onConnectSuccess");
            setBtnConnectName(1);  //1显示断开连接;2显示:连接服务
            connectFlag = true;
        }

        public void onConnectFail(Throwable e, String message){
            Log.e(TAG, "onConnectFail");
            logClient(getTime() +"onConnectFail "+message);
            setBtnConnectName(2);  //1显示断开连接;2显示:连接服务
            connectFlag = false;
        }

        public void onConnectError(Throwable e, String message)
        {
            Log.e(TAG, "onConnectError");
            logClient(getTime() +"onConnectError "+message);
            setBtnConnectName(2);  //1显示:断开连接;2显示:连接服务
            connectFlag = false;
        }

        public void onMessage(String message){
            Log.e(TAG, "onMessage");
            logClient(getTime() +"onMessage: " + message);
        }
    }

    private void getClientPort() {
        mClientPort = Integer.parseInt(mEdClientPort.getText().toString().trim());
    }

    private void getClientIp() {
        mClientIp = mEdClientIp.getText().toString().trim();
    }
    private void getClientSendMessage() {
        mClientSendMessage = mEdClientSendMessage.getText().toString().trim();
    }
    /**
     * 获取WIFI下ip地址
     */
    private String getLocalIpAddress() {
        WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        // 获取32位整型IP地址
        int ipAddress = wifiInfo.getIpAddress();

        //返回整型地址转换成“*.*.*.*”地址
        return String.format("%d.%d.%d.%d",
                (ipAddress &amp; 0xff), (ipAddress >> 8 &amp; 0xff),
                (ipAddress >> 16 &amp; 0xff), (ipAddress >> 24 &amp; 0xff));
    }

    public void connectServer(View view) {
        if( (connectFlag==false) &amp;&amp; (btn_start_client.getText().equals("连接服务")) ){
            getClientIp();
            getClientPort();
            tcpClient.connect(mClientIp,mClientPort, onTcpClientConnectListener);
        }
        else if( (connectFlag==true) &amp;&(btn_start_client.getText().equals("断开连接")) ){
            Log.e(TAG, "断开连接");
            tcpClient.disconnect();
        }

    }

    //发送信息服务器
    public void SendMsgToServer(View view) {
        if (connectFlag==true) {
            getClientSendMessage();
            tcpClient.sendMessage(mClientSendMessage);

        }
    }

    //清楚日志
    public void clearLog(View view) {
        mClientMessageList.clear();
        mClientMessageAdapter.notifyDataSetChanged();
    }

    private void logClient(final String log) {
        if (!isCurrentlyOnMainThread()) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    logClientReal(log);
                }
            });
        } else {
            logClientReal(log);
        }
    }

    private void logClientReal(final String log) {
        Log.d(TAG, log);
        mClientMessageList.add(0, log);
        mClientMessageAdapter.notifyDataSetChanged();
    }

    //连接服务器设置btnConnect的名字提醒已连接获断开
    private void setBtnConnectName(final int iType) {
        if (!isCurrentlyOnMainThread()) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    setBtnConnectNameReal(iType);
                }
            });
        } else {
            setBtnConnectNameReal(iType);
        }
    }

    private void setBtnConnectNameReal(final int iType) {
        Log.d(TAG, String.valueOf(iType));
        if(iType==1)
        {
            btn_start_client.setText("断开连接");
        }
        else if(iType==2){
            btn_start_client.setText("连接服务");
        }
    }

    /**
     * 判断当前线程是否主线程
     */
    private boolean isCurrentlyOnMainThread() {
        return Looper.myLooper() == Looper.getMainLooper();
    }

    /**
     * 获取当前时间
     */
    private String getTime() {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss.SSS", Locale.CHINA);
        return format.format(new Date());
    }
}

(2)

package com.example.chentcpclientsenior;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;


public class TcpClient {
	private static final String TAG = "TcpClient";
	private static TcpClient mTcpClient = new TcpClient();
	private ClientSocketThread mClientSocketThread;
	private OnConnectListener mOnConnectListener;

	public static TcpClient getInstance() {
		return mTcpClient;
	}


	public void setOnConnectListener(OnConnectListener onConnectListener) {
		mOnConnectListener = onConnectListener;
	}

	public interface OnConnectListener {
		/**
		 * @param inetAddress  服务端地址
		 * @param localAddress 客户端地址
		 */
		void onConnectSuccess(String inetAddress, String localAddress);

		void onConnectFail(Throwable e, String message);

		void onConnectError(Throwable e, String message);

		void onMessage(String message);
	}

	public void setIp(String ip) {
		mClientIp = ip;
	}

	public void setPort(int port) {
		mClientPort = port;
	}

	public void connect() {
		if (mOnConnectListener == null) {
			throw new RuntimeException("请设置OnConnectListener");
		}
		if (mClientIp == null || mClientIp.length() == 0 || mClientPort == 0) {
			mOnConnectListener.onConnectFail(new RuntimeException("请设置ip与port"), "请设置ip与port");
			return;
		}
		if (mClientSocketThread == null) {
			mClientSocketThread = new ClientSocketThread();
			mClientSocketThread.start();
		} else {
			mOnConnectListener.onConnectError(new RuntimeException("已经建立连接"), "已经建立连接");
		}
	}

	public void connect(String ip, int port, OnConnectListener onConnectListener) {
		mOnConnectListener = onConnectListener;
		mClientIp = ip;
		mClientPort = port;
		connect();
	}

	public void disconnect() {
		if (mOnConnectListener == null) {
			throw new RuntimeException("请设置OnConnectListener");
		}
		if (mClientSocket != null) {
			try {
				mClientSocket.close();
				mClientIn.close();
				mClientOut.close();
				mClientOut = null;
				mClientIn = null;
				mClientSocket = null;
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			mOnConnectListener.onConnectError(new RuntimeException("已经断开连接"), "已经断开连接");
		}
		mClientSocketThread.runnable.stopRun();
		if (mClientSocketThread != null) {
			mClientSocketThread = null;
		}
	}

	public void sendMessage(String message) {
		if (mOnConnectListener == null) {
			throw new RuntimeException("请设置OnConnectListener");
		}
		mClientSendMessage = message;
		clientSendMessage();
	}

	private void insideDisconnect() {
		if (mClientSocket != null) {
			try {
				mClientSocket.close();
				mClientIn.close();
				mClientOut.close();
				mClientOut = null;
				mClientIn = null;
				mClientSocket = null;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (mClientSocketThread != null) {
			mClientSocketThread = null;
		}
	}
	//=================================================================================
	// Client
	//=================================================================================

	private String mClientIp;
	private int mClientPort;
	private Socket mClientSocket;
	private BufferedReader mClientIn;
	private PrintWriter mClientOut;
	private String mClientSendMessage;

	class ClientSocketThread extends Thread {
		ClientReceiverRunnable runnable;
		@Override
		public void run() {
			try {
				mClientSocket = new Socket(mClientIp, mClientPort);
				mClientIn = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
				mClientOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mClientSocket.getOutputStream())), true);
				//ClientReceiverRunnable runnable = new ClientReceiverRunnable(mClientSocket);
				runnable = new ClientReceiverRunnable(mClientSocket);
				new Thread(runnable).start();
				if (mOnConnectListener != null) {
					mOnConnectListener.onConnectSuccess(mClientSocket.getInetAddress().getHostAddress(), mClientSocket.getLocalAddress().getHostAddress());
				}
			} catch (IOException e) {
				if (mOnConnectListener != null) {
					mOnConnectListener.onConnectFail(e, "服务器没有开启");
				}
				insideDisconnect();
				e.printStackTrace();
			}
		}
	}

	class ClientReceiverRunnable implements Runnable {
		boolean isContinue = true;
		char cb[]= new char[2000];   //暂时设定最大接收2000byte
		int iReceiveCount=0;
		private Socket socket;

		public ClientReceiverRunnable(Socket socket) {
			this.socket = socket;
		}
		public void stopRun()
		{
			isContinue = false;
		}
		@Override
		public void run() {
//			boolean isContinue = true;
			while (isContinue) {
				try {
					if (socket != null && !socket.isClosed() && socket.isConnected() && !socket.isInputShutdown()) {
						String clientReceiverMessage;
						//if ((clientReceiverMessage = mClientIn.readLine()) != null) {//服务器断开连接时,读取内容为null,这与发送消息为“”不同
						iReceiveCount=mClientIn.read(cb);
						if(iReceiveCount>0){
							char showCb[] = new char[iReceiveCount];
							//public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
							System.arraycopy(cb, 0, showCb, 0, iReceiveCount);
							clientReceiverMessage = String.valueOf(showCb);
							// 客户端接收到消息
							if (mOnConnectListener != null) {
								mOnConnectListener.onMessage(clientReceiverMessage);
							}
						} else {
							//服务端断开连接
							isContinue = false;
							if (mOnConnectListener != null) {
								mOnConnectListener.onConnectError(new RuntimeException("服务器断开连接"), "服务器断开连接");
							}
							insideDisconnect();
						}
					}
				} catch (Exception e) {
					isContinue = false;
					e.printStackTrace();
					if (mOnConnectListener != null) {
						mOnConnectListener.onConnectError(e, "客户端连接超时");
					}
				}
			}
			try {
				if (socket != null) {
					socket.close();
				}
				if (mClientIn != null) {
					mClientIn.close();
				}
				if (mClientOut != null) {
					mClientOut.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void clientSendMessage() {
		if (mClientSendMessage == null || mClientSendMessage.length() == 0) {
			if (mOnConnectListener != null) {
				mOnConnectListener.onConnectError(new RuntimeException("请输入内容"), "请输入内容");
			}
			return;
		}
		if (mClientSocket != null && mClientSocket.isConnected() && !mClientSocket.isOutputShutdown()
				&& mClientOut != null) {
			mClientOut.println(mClientSendMessage);
		} else {
			if (mOnConnectListener != null) {
				mOnConnectListener.onConnectError(new RuntimeException("客户端已经断开连接"), "客户端已经断开连接");
			}
		}
	}

}

4、注意权限设置

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

 

原文地址:https://blog.csdn.net/chencaw/article/details/122981311

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_39434.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注