网络通信是我们日常生活中必不可少的,例如QQ和微信,几乎可以通过socket服务器进行连接,以此达到进行实时对话的作用。
服务端的代码(idea):
这里要先开启idea中服务端的接口,从而做到前后端的交互:
package com.socketio.server;
import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
public class SocketServer {
public static void main(String[] args) {
Configuration config = new Configuration();
// 如果调用了setHostname方法,就只能通过主机名访问,不能通过IP访问
//config.setHostname("localhost");
config.setPort(9010); // 设置监听端口
final SocketIOServer server = new SocketIOServer(config);
// 添加连接连通的监听事件
server.addConnectListener(client -> {
System.out.println(client.getSessionId().toString()+"已连接");
});
// 添加连接断开的监听事件
server.addDisconnectListener(client -> {
System.out.println(client.getSessionId().toString()+"已断开");
});
// 添加文本发送的事件监听器
server.addEventListener("send_text", String.class, (client, message, ackSender) -> {
System.out.println(client.getSessionId().toString()+"发送文本消息:"+message);
client.sendEvent("receive_text", "我已收到,马上做出回应。");
});
// 添加图像发送的事件监听器
server.addEventListener("send_image", JSONObject.class, (client, json, ackSender) -> {
String desc = String.format("%s,序号为%d", json.getString("name"), json.getIntValue("seq"));
System.out.println(client.getSessionId().toString()+"发送图片消息:"+desc);
client.sendEvent("receive_image", json);
});
server.start(); // 启动Socket服务
}
}
注意端口一定要与客户端的一致,这里写的是当你输入内容发送后会自动从服务端中进行回复,未来可通过接入ai(例如讯飞星火)来进行多样式的对话。
客户端代码(Android studio)
1.创建dateuitl,获取当前时间
package com.example.newsoket;
import android.annotation.SuppressLint;
import java.text.SimpleDateFormat;
import java.util.Date;
@SuppressLint("SimpleDateFormat")
public class DateUtil {
// 获取当前的日期时间
public static String getNowDateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
return sdf.format(new Date());
}
// 获取当前的时间
public static String getNowTime() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date());
}
// 获取当前的分钟
public static String getNowMinute() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
return sdf.format(new Date());
}
// 获取当前的时间(精确到毫秒)
public static String getNowTimeDetail() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
return sdf.format(new Date());
}
// 将长整型的时间数值格式化为日期时间字符串
public static String formatDate(long time) {
Date date = new Date(time);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
}
2.创建NetConst ,初始化端口和IP地址
package com.example.newsoket;
public class NetConst {
// HTTP地址的前缀
public final static String HTTP_PREFIX = "http://192.168.1.7:8080/HttpServer/";
// WebSocket服务的前缀
public final static String WEBSOCKET_PREFIX = "ws://192.168.1.7:8080/HttpServer/";
public final static String BASE_IP = "192.168.1.7"; // 基础Socket服务的ip
public final static int BASE_PORT = 9010; // 基础Socket服务的端口
public final static String CHAT_IP = "192.168.1.7"; // 聊天Socket服务的ip
public final static int CHAT_PORT = 9011; // 聊天Socket服务的端口
}
3.创建SocketUtil 与socket连接进行判断
package com.example.newsoket;
import android.app.Activity;
import android.widget.Toast;
import com.google.gson.Gson;
import org.json.JSONObject;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import io.socket.client.Socket;
public class SocketUtil {
// 把对象数据转换为json串,然后发给Socket服务器
public static void emit(Socket socket, String event, Object obj) {
try {
JSONObject json = new JSONObject(new Gson().toJson(obj));
socket.emit(event, json);
} catch (Exception e) {
e.printStackTrace();
}
}
// 判断Socket能否连通
public static void checkSocketAvailable(Activity act, String host, int port) {
new Thread(() -> {
try (java.net.Socket socket = new java.net.Socket()) {
SocketAddress address = new InetSocketAddress(host, port);
socket.connect(address, 1500);
} catch (Exception e) {
e.printStackTrace();
act.runOnUiThread(() -> {
Toast.makeText(act, "无法连接Socket服务器", Toast.LENGTH_SHORT).show();
});
}
}).start();
}
}
4.创建sockettake.activity进行交互
xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/editext_selector"<!可有可无,可以改为自己想要的>
android:hint="请输入聊天内容"
android:textColor="@color/black"
android:textSize="17sp" />
<Button
android:id="@+id/btn_send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送文本消息"
android:textColor="@color/black"
android:textSize="17sp" />
<TextView
android:id="@+id/tv_response"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
java:
package com.example.newsoket;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.newsoket.NetConst;
import com.example.newsoket.DateUtil;
import com.example.newsoket.SocketUtil;
import java.net.URISyntaxException;
import io.socket.client.IO;
import io.socket.client.Socket;
import java.net.URISyntaxException;
public class Sockettext extends AppCompatActivity {
private static final String TAG = "SocketioTextActivity";
private EditText et_input; // 声明一个编辑框对象
private TextView tv_response; // 声明一个文本视图对象
private Socket mSocket; // 声明一个套接字对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sockettext);
et_input = findViewById(R.id.et_input);
tv_response = findViewById(R.id.tv_response);
findViewById(R.id.btn_send).setOnClickListener(v -> {
String content = et_input.getText().toString();
if (TextUtils.isEmpty(content)) {
Toast.makeText(this, "请输入聊天消息", Toast.LENGTH_SHORT).show();
return;
}
mSocket.emit("send_text", content); // 往Socket服务器发送文本消息
});
initSocket(); // 初始化套接字
}
// 初始化套接字
private void initSocket() {
// 检查能否连上Socket服务器
SocketUtil.checkSocketAvailable(this, NetConst.BASE_IP, NetConst.BASE_PORT);
try {
String uri = String.format("http://%s:%d/", NetConst.BASE_IP, NetConst.BASE_PORT);
mSocket = IO.socket(uri); // 创建指定地址和端口的套接字实例
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
mSocket.connect(); // 建立Socket连接
// 等待接收传来的文本消息
mSocket.on("receive_text", (args) -> {
String desc = String.format("%s 收到服务端消息:%s",
DateUtil.getNowTime(), (String) args[0]);
runOnUiThread(() -> tv_response.setText(desc));
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mSocket.off("receive_text"); // 取消接收传来的文本消息
if (mSocket.connected()) { // 已经连上Socket服务器
mSocket.disconnect(); // 断开Socket连接
}
mSocket.close(); // 关闭Socket连接
}
}
这样,一个简单的socket交互就完成了。
尾言
由于作者设备的原因,无论是用真机还是模拟器,客户端都连接不上服务器,所以现在放不出运行图,但是代码是正常运行的,希望有了解前后端交互的伙伴能够帮作者一下,十分感谢。