Android-socket-client客户端<2>

————————————————————————————————————————————————————————————————————

前言:参考老师的代码重新修改了一下我的客户端程序,将socket封装成了一个类,还自定义了一个接口,其中的接口函数当做回调函数。



MySocket.java:声明了一个MySocket的类,提供了自己定义的一些网络连接,传输等接口函数,继承了系统的Socket类。


NetworkInterface.java:自己定义了一个接口类,里面定义了几个接口函数:(作为MySocket类中函数的回调函数)

public void NetConnected();  //网络连接成功
public void NetConnectFail();//网络连接失败
public void NetReceived(String msg);//网络接收到数据
public void NetSent();//网络发送数据成功


NetworkProber.java:NetworkProber这个类是用来检查网络是否可用的,是GPS还是WIFI,目前代码中并没用到。


MainActivity.java:实现了主要的代码,调用自定义的socket类去实现socket客户端与服务器之间发送信息


总结:1.这个代码体现了面向对象的语言好处,把一个自己需要的东西封装成了一个类,等我要用的时候,不用再重复去敲具体的实现代码,只需要调用我们类中的接口函数就好。

         2. 这里定义接口是为了使用其接口方法当做回调函数


首先我们看一下接口的使用: (定义了一个该接口类型的变量,就会发现自动实现了我们的接口函数)


是不是跟我们定义一个按键的响应一样,它会自动出现onclick这个函数


然后就是回调:这里我举一个代码中的小例子看,(在MySocket中定义的一个连接网络的方法,它用到了一个线程,这个线程中就用到了接口定义的函数当做回调函数)


你们可以看到当连接成功的时候会自动去调用NetConnected()这个函数,这个函数是我们在NetInterface.java中看到的定义的接口函数;当连接失败的时候调用NetConnectFail()这个函数.


然后在ui线程去点连接:


当你一点击连接,它就会调用MyNetConnect这个方法,去使用线程去连接,当成功的时候会回调那个成功的接口函数,失败则回调我们那个失败的接口函数。我们之所以用这2个回调函数,是因为我们当连接失败的时候我们需要知道,成功了我们也需要知道,而这2个回调函数的作用就在于我们来通知用户。


上面这2个回调函数的实现就是来告诉我们连接是成功还是失败(通过handler,具体看代码)


通过上面的解释,我想大家应该能明白回调的意思了吧,首先回调函数不是一种具体的函数,什么函数都可以做为回调函数,就比如这里我定义的接口函数<所以我上面把NetConnectFail() NetConnected()叫做接口函数或者回调函数>。老师打了一个比喻说就相当于我们语文中用插入符号插入一些话,一句话写完,你或许想加一点什么东西,就需要用那个符号插入我们想要的话,这就相当于回调。

如果还不能理解的话,可以把我的代码仔细看一看,看看NetConnectFail() NetConnected()这2个函数是如果调用的,如果实现的,应该差不多了吧。


*****************************************************************************************************************************************************************************************

贴上效果图:(服务端仍然用的那个串口小助手)



*****************************************************************************************************************************************************************************************

贴上代码:(记得在AndroidMainifest.xml中添加权限,这里我就不贴了,上篇中有)

(布局文件)

<RelativeLayout 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:background="@drawable/bk"
    tools:context="${relativePackage}.${activityClass}" 
    >

    <EditText
        android:id="@+id/ip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/con_btn"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" 
        android:layout_alignParentTop="true"
        android:layout_toLeftOf="@+id/con_btn"
        android:layout_toStartOf="@+id/con_btn"
        android:hint="请输入服务器ip地址"
	android:textColorHint="#ffffff"
        android:ems="10" 
        />

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/send_btn"
        android:layout_alignParentEnd="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentStart="true"
        android:ems="10"
        android:hint="编辑内容"
        android:textColorHint="#000000" >
        <requestFocus />
    </EditText>

   

    <Button
        android:id="@+id/send_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" 
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_marginBottom="28dp"
        android:text="发送" 
        android:textStyle="bold"
        android:background="@drawable/btn"
        />

    <Button
        android:id="@+id/con_btn"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toLeftOf="@+id/discon_btn"
        android:layout_toStartOf="@+id/discon_btn"
        android:text="连接"
        android:textStyle="bold" />

    <Button
        android:id="@+id/discon_btn"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/con_btn"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" 
        android:layout_alignParentTop="true"
        android:text="断开"
        android:textStyle="bold"

        />

    <!-- 设置textview下拉属性 scrollbars  “滚动条出现到消失的时间=5000ms” -->

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/editText"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_below="@+id/port"
        android:scrollbarFadeDuration="5000"
        android:scrollbarStyle="insideOverlay"
        android:scrollbars="vertical"
        android:textColorHint="#ffffff"
        android:hint="数据收发区"
        />

    <EditText
        android:id="@+id/port"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/ip"
        android:layout_toLeftOf="@+id/con_btn"
        android:layout_toStartOf="@+id/con_btn" 
        android:ems="10"
        android:hint="请输入服务器端口号"
        android:textColorHint="#ffffff"
        android:inputType="number" 
        />

    <TextView
        android:id="@+id/text_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/port"
        android:layout_alignLeft="@+id/con_btn"
        android:layout_alignTop="@+id/port"
        android:layout_toLeftOf="@+id/discon_btn"
        android:hint="状态:"
        android:textColorHint="#545454"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/text_status1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/port"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/con_btn" 
        android:textSize="17sp" />

</RelativeLayout>


MySocket.java:

package com.lzj_socket;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

import android.util.Log;

public class MySocket {

	private Socket socketFd = null;
	/*
	 * 不同方法的网络收发接口函数
	 * DataOutputStream 发送字节流数据
	 * DataInputStream    接收字节流数据
	 * 
	 * BufferedReader      接收字符流数据
	 * BufferedWriter       发送字符流数据
	 * */
	
	private DataOutputStream socketWriter = null;//DataOutputStream 用于推送消息  
	private BufferedReader socketReader = null;//BufferedReader 用于接收消息
	
	private NetworkInterface netCallback = null; // 定义外部接口函数变量(回调函数)
	private static final String bm="gb2312"; //中文字符编码格式
	
	//该类提供给外部的接口函数
	public MySocket(){ //不带参数的构造函数	
	};
	
	//该类提供给外部的接口函数
	public MySocket(NetworkInterface callback){ //带参数的构造函数
		netCallback = callback; //设置外部接口函数
	}
	
	/*
	 * 该类提供给外部的接口函数---网络连接接口函数
	 * 
	 * 传入参数:
	 * ip 		: 服务器IP地址
	 * port	: 服务器端口号
	 * timeout:连接超时时间,即如果连接不上多长时间结束连接动作
	 */
	public void MyNetConnect(String ip, int port , int timeout){
		myNetConnThread netConnect = new myNetConnThread(ip, port, timeout);
		netConnect.start();
	}
	
	/*
	 * 该类提供给外部的接口函数 -- 网络接收数据线程启动
	 * 
	 * 传入参数:无
	 */
	public void MyNetReceiver(){
		myNetRecvThread netRecvThread = new myNetRecvThread();
		netRecvThread.start();
	}
	
	/*
	 * 该类提供给外部的接口函数---网络数据发送函数
	 * 
	 * 传入参数:
	 * msg 	: 需要发送的字符数据流
	 */
	public void MyNetSendMsg(String msg){
		if(null != socketWriter && null != msg){
			//发送信息到服务端				
			try {
				socketWriter.write(msg.getBytes(bm));
				socketWriter.flush(); // 清空发送缓存
				netCallback.NetSent(); // 调用接口函数,通知上层发送成功
				Log.e("MySocket", "Send-> "+msg);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}				
		}
	}
	
	/*
	 * 该类提供给外部的接口函数 -- 网络资源释放
	 * 	网络连接如果不使用了,是必须释放所占用的连接资源
	 * 传入参数:无
	 */
	public void MyNetRelease(){
		try {
			if(null != socketFd){
				socketWriter.close();
				socketReader.close();
				socketFd.close();
			}		
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//该类内部使用的网络连接线程方法
	class myNetConnThread extends Thread{
		private String strIP = null;
		private int iPort = 0, iTimeout = 5000;
		
		public myNetConnThread(String ip, int port , int timeout){// 线程类myNetConnThread的带参构造函数
			strIP = ip; iPort = port; iTimeout = timeout;
		}
		
		public void run(){
			try {
				socketFd = new Socket();
				//连接指定的服务器
				socketFd.connect(new InetSocketAddress(strIP, iPort), iTimeout);
				socketFd.setSoTimeout(iTimeout); //设置网络收发超时时间
				
				OutputStream outStream = socketFd.getOutputStream();
				socketWriter = new DataOutputStream(outStream);
				
				//InputStream inputStream = socketFd.getInputStream();
				//socketReader = new DataInputStream(inputStream);
				
				socketReader = new BufferedReader(new InputStreamReader(socketFd.getInputStream(),bm));
				netCallback.NetConnected();// 调用接口函数,通知上层连接成功
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				netCallback.NetConnectFail();
			}
			
		}
	}
	//该类内部使用的网络接收线程方法
	class myNetRecvThread extends Thread{
		public void run(){
			if(null != socketReader){
				//读取发来服务器信息
				while(true){
					try {
						Thread.sleep(100);
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					try {
						
						if(socketReader.ready()){
							/*
							 * readLine()为阻塞函数,如果接收的数据流没有结束符(回车换行符)‘\n or \r’
							 *该函数会一直等待(即阻塞在当前代码处),直到到达所设置的超时时间后抛出错误提示
							 **/
							String data = socketReader.readLine(); 
							netCallback.NetReceived(data); // 调用接口函数,通知上层有数据接收成功
						}
		
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
						Log.e("MySocket", "receiver error");
						return ;
					}	
				}			
			}
		}
	}
}


NetworkInterface.java:
package com.lzj_socket;


	public interface NetworkInterface {
		/*
		 * 定义接口函数
		*/	
			public void NetConnected();  //网络连接成功
			public void NetConnectFail();//网络连接失败
			public void NetReceived(String msg);//网络接收到数据
			public void NetSent();//网络发送数据成功
		}


MainActivity.java:

package com.lzj.example.msocketclient;

import com.lzj_socket.NetworkInterface;
import com.lzj_socket.MySocket;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

@SuppressLint("HandlerLeak")
public class MainActivity extends Activity {	
	private EditText ip=null,port=null;
	private EditText editTest=null;
	private TextView text=null,status=null;
	private Button   send_btn=null,con_btn=null,discon_btn=null;	
	private MySocket myNet = null;//自定义的网络接口类
	private NetworkInterface netCallback = null; // 自定义的网络接口函数
	

	
	public Handler myHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if(msg.what == 1){
				Toast.makeText(MainActivity.this,"连接成功" ,Toast.LENGTH_SHORT).show();
				status.setText("已连接");
			}else if(msg.what == 2){
				Toast.makeText(MainActivity.this,"连接失败" ,Toast.LENGTH_SHORT).show();
				status.setText("未连接");
			}else if (msg.what == 3) {
				Bundle bundle = msg.getData();
				text.append("服务器:"+bundle.getString("msg")+"\n");
			}
		}
	};

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_lmain);
		ip=(EditText)findViewById(R.id.ip);
		port=(EditText)findViewById(R.id.port);
		editTest=(EditText)findViewById(R.id.editText);
		text=(TextView)findViewById(R.id.textView);
		status=(TextView)findViewById(R.id.text_status1);
		
		status.setText("未连接");
		text.setMovementMethod(ScrollingMovementMethod.getInstance());
		
		
				
		con_btn=(Button)findViewById(R.id.con_btn);
		con_btn.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				String Ip = ip.getText().toString();
				int Port = Integer.parseInt(port.getText().toString());
				myNet.MyNetConnect(Ip, Port, 3000);
				send_btn.setEnabled(true);
				editTest.setEnabled(true);											
			}
		});	
		
		send_btn=(Button) findViewById(R.id.send_btn);
		send_btn.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				myNet.MyNetSendMsg(editTest.getText().toString().trim());
				text.append("本机:"+editTest.getText().toString()+"\n");
			}
		});
		
		discon_btn=(Button)findViewById(R.id.discon_btn);
		discon_btn.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				myNet.MyNetRelease();
				Toast.makeText(MainActivity.this,"断开连接" ,Toast.LENGTH_SHORT).show();
			    status.setText("未连接");
				send_btn.setEnabled(false);
				editTest.setEnabled(false);
			}
		});
		send_btn.setEnabled(false);
		editTest.setEnabled(false);
		
		/*网络接口函数初始化---提示信息*/
		netCallback = new NetworkInterface(){
			public void NetConnected() {
				Message message = new Message();
				message.what = 1;
				myHandler.sendMessage(message);			
				myNet.MyNetReceiver();
				
			}

			@Override
			public void NetConnectFail() {
				Message message = new Message();
				message.what = 2;
				myHandler.sendMessage(message);
				
			}

			@Override
			public void NetReceived(String msg) {
				Message message = new Message();
				message.what = 3; // 设置消息what标签
				Bundle bundle = new Bundle();
				bundle.clear();
				bundle.putString("msg", msg);
				message.setData(bundle);//设置消息内容
				//发送消息 修改UI线程中的组件
				myHandler.sendMessage(message);
				
			}

			@Override
			public void NetSent() {
				Toast.makeText(MainActivity.this,"信息发送成功" ,Toast.LENGTH_SHORT).show();
			}		
		};	
		myNet = new MySocket(netCallback);	
	}
	protected void onDestroy(){
		super.onDestroy();
		myNet.MyNetRelease(); // 释放网络连接资源
		Log.d("lzj", "Connect Release");
	} 
}
















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面我会分别给您提供 Java 实现的 Socket 服务器和 Android Socket 客户端示例代码。 Java 实现的 Socket 服务器 ```java import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class SocketServer { public static void main(String[] args) throws IOException { // 创建一个 ServerSocket,监听指定端口 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("Socket 服务器已启动,等待客户端连接..."); // 等待客户端连接 Socket socket = serverSocket.accept(); System.out.println("客户端已连接:" + socket.getInetAddress().getHostAddress()); // 获取输入流和输出流 InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); // 读取客户端发送的数据 byte[] buffer = new byte[1024]; int len = inputStream.read(buffer); String message = new String(buffer, 0, len); System.out.println("收到客户端消息:" + message); // 发送响应数据给客户端 String response = "Hello, Client!"; outputStream.write(response.getBytes()); // 关闭资源 outputStream.close(); inputStream.close(); socket.close(); serverSocket.close(); System.out.println("Socket 服务器已关闭"); } } ``` Android Socket 客户端示例代码 ```java import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private EditText mEtServerIp; private EditText mEtServerPort; private EditText mEtMessage; private Button mBtnSend; private TextView mTvResponse; private Socket mSocket; private InputStream mInputStream; private OutputStream mOutputStream; private static final int MSG_RECEIVED = 1; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_RECEIVED: String message = (String) msg.obj; mTvResponse.setText(message); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEtServerIp = findViewById(R.id.et_server_ip); mEtServerPort = findViewById(R.id.et_server_port); mEtMessage = findViewById(R.id.et_message); mBtnSend = findViewById(R.id.btn_send); mTvResponse = findViewById(R.id.tv_response); mBtnSend.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_send: new Thread(new Runnable() { @Override public void run() { try { // 获取服务端 IP 和端口号 String serverIp = mEtServerIp.getText().toString().trim(); int serverPort = Integer.parseInt(mEtServerPort.getText().toString().trim()); // 创建 Socket 连接 mSocket = new Socket(serverIp, serverPort); // 获取输入流和输出流 mInputStream = mSocket.getInputStream(); mOutputStream = mSocket.getOutputStream(); // 发送消息给服务端 String message = mEtMessage.getText().toString().trim(); mOutputStream.write(message.getBytes()); // 读取服务端响应消息 byte[] buffer = new byte[1024]; int len = mInputStream.read(buffer); String response = new String(buffer, 0, len); // 发送消息给主线程更新 UI Message msg = mHandler.obtainMessage(MSG_RECEIVED, response); mHandler.sendMessage(msg); } catch (IOException e) { e.printStackTrace(); } finally { try { if (mSocket != null) { mSocket.close(); } if (mOutputStream != null) { mOutputStream.close(); } if (mInputStream != null) { mInputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } }).start(); break; } } } ``` 以上代码仅供参考,具体实现要根据您的需求和具体情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值