先上传一张效果图
权限
客户端状态接口
public interface IClientStatus {
void startClientConn();//启动客户端Socket连接
void connectSuccess();//连接服务器成功
void connectFailed();//连接服务器失败
void receivedMsg(String msg);//接收服务器发送给客户端的数据
}
服务端状态接口
public interface IServerStatus {
void waitClientConn();//服务器等待客户端连接
void clientConnectted();//客户端已连接
void receivedMsg(String msg);//接收到客户端发送给服务器的数据
}
服务端核心代码
public class TcpServer {
private static ServerSocket serverSocket;
private static Socket socket;
public static void startServer(final IServerStatus serverStatus){
if (serverSocket == null){
new Thread(new Runnable() {
@Override
public void run() {
try {
serverSocket = new ServerSocket(8080);
serverStatus.waitClientConn();
while (true){
socket = serverSocket.accept();
serverStatus.clientConnectted();
receivedMsg(serverStatus);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* 接收数据
* @param serverStatus
*/
private static void receivedMsg(final IServerStatus serverStatus){
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
String data = new String(buffer, 0, len);
serverStatus.receivedMsg(data);
}
// 关闭输入流
//socket.shutdownInput();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
socket = null;
}
}
}).start();
}
public static void sendTcpMessage(final String msg){
if (socket != null && socket.isConnected()) {
new Thread(new Runnable() {
@Override public void run() {
try {
socket.getOutputStream().write(msg.getBytes());
socket.getOutputStream().flush();
//关闭输出流
//socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
这里需要特别注意的是:
在使用accept函数的时候,如果服务器面向多个客户的连接
- 必须使用while循环,每次循环阻塞在accept函数,等待新的连接到来,这样才能返回新的socket。如果不使用while死循环每次阻塞在accept函数,也可以面向多个客户连接,此时将在socket抽象层,自动建立socket,并且该socket不受控制
- 必须使用数组(或其他数据结构)保存当前accept创建的socket,否则下次新的socket建立后,当前的socket将不受控制。
客户端核心代码
public class TcpClient {
public static Socket socket;
public static void startClient(final String address , final int port, final IClientStatus clientStatus){
if (address == null){
return;
}
if (socket == null) {
new Thread(new Runnable() {
@Override public void run() {
try {
clientStatus.startClientConn();//启动客户端
socket = new Socket(address, port);
clientStatus.connectSuccess();
InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
String data = new String(buffer, 0, len);
clientStatus.receivedMsg(data);
}
} catch (Exception e) {
e.printStackTrace();
clientStatus.connectFailed();
}finally {
clientStatus.connectFailed();
if(socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
socket = null;
}
}
}).start();
}
}
public static void sendTcpMessage(final String msg){
if (socket != null && socket.isConnected()) {
new Thread(new Runnable() {
@Override public void run() {
try {
socket.getOutputStream().write(msg.getBytes());
socket.getOutputStream().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
调用
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btnStartServer;
private Button btnSrartClient;
private Button btnSendToServer;
private Button btnSendToClient;
private TextView server_status;
private TextView client_status;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStartServer = findViewById(R.id.btn_start_server);
btnStartServer.setOnClickListener(this);
btnSrartClient = findViewById(R.id.btn_start_client);
btnSrartClient.setOnClickListener(this);
btnSendToServer = findViewById(R.id.btn_send_server);
btnSendToServer.setOnClickListener(this);
btnSendToClient = findViewById(R.id.btn_send_client);
btnSendToClient.setOnClickListener(this);
server_status = findViewById(R.id.server_status);
client_status = findViewById(R.id.client_status);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_start_server:
//开启服务器
TcpServer.startServer(new IServerStatus() {
@Override
public void waitClientConn() {
//服务器等待客户端连接
runOnUiThread(new Runnable() {
@Override
public void run() {
server_status.setText("服务器等待客户端连接");
}
});
}
@Override
public void clientConnectted() {
//客户端已连接
runOnUiThread(new Runnable() {
@Override
public void run() {
server_status.setText("客户端已连接");
}
});
}
@Override
public void receivedMsg(final String msg) {
//接收到客户端发送过来的数据
runOnUiThread(new Runnable() {
@Override
public void run() {
server_status.setText("msg:"+msg);
}
});
}
});
break;
case R.id.btn_start_client:
//连接客户端
TcpClient.startClient(getIpAddressByWifi(), 8080, new IClientStatus() {
@Override
public void startClientConn() {
runOnUiThread(new Runnable() {
@Override
public void run() {
client_status.setText("开启连接服务器!");
}
});
}
@Override
public void connectSuccess() {
runOnUiThread(new Runnable() {
@Override
public void run() {
client_status.setText("连接服务器成功!");
}
});
}
@Override
public void connectFailed() {
runOnUiThread(new Runnable() {
@Override
public void run() {
client_status.setText("连接服务器失败!");
}
});
}
@Override
public void receivedMsg(final String msg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
client_status.setText("msg:"+msg);
}
});
}
});
break;
case R.id.btn_send_server:
//发送数据给服务器
TcpClient.sendTcpMessage("当前时间戳:"+System.currentTimeMillis());
break;
case R.id.btn_send_client:
//发送数据给客户端
TcpServer.sendTcpMessage("当前时间戳:"+System.currentTimeMillis());
break;
}
}
/**
* 通过 wifi 获取本地 IP 地址
*
* @return IP 地址
*/
public String getIpAddressByWifi() {
// 获取wifi服务
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
// 判断wifi是否开启
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
return intToIp(ipAddress);
}
private String intToIp(int i) {
return (i & 0xFF) + "." +
((i >> 8) & 0xFF) + "." +
((i >> 16) & 0xFF) + "." +
(i >> 24 & 0xFF);
}
}
以上就是本人整理打小demo了。