Android——socket连接(客户端发消息给服务端)
程序员文章站
2022-05-21 13:44:06
...
准备工作
一台手机作服务端,一台手机作客户端,两部手机连接同一个wifi
服务端
布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.jie.socketdemo.MainActivity">
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@+id/info"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
private TextView mTvInfo;
private TextView mTvGetData;
private ServerSocket mServerSocket = null;
private InputStream mInputSteam;
private String ip;
private int port;
StringBuffer mStringBuffer = new StringBuffer();
public Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
//本地ip和port信息
mTvInfo.setText(msg.obj.toString());
break;
case 2:
//从客户端获取到的消息
mTvGetData.setText("CustomInfo:"+msg.obj.toString());
mStringBuffer.setLength(0);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvInfo = findViewById(R.id.info);
mTvGetData = findViewById(R.id.data);
receiveData();
}
/**
* 服务器端接收数据
* 需要注意以下一点:
* 服务器端应该是多线程的,因为一个服务器可能会有多个客户端连接在服务器上;
*/
public void receiveData() {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
/*指明服务器端的端口号*/
try {
mServerSocket = new ServerSocket(8000);
} catch (IOException e) {
e.printStackTrace();
}
getLocalIpAddress(mServerSocket);
Message msg = handler.obtainMessage();
msg.what = 1;
msg.obj = "IP:" + ip + " , PORT: " + port;
handler.sendMessage(msg);
//持续获取消息
while (true) {
Socket socket = null;
try {
if (mServerSocket != null) {
socket = mServerSocket.accept();
mInputSteam = socket.getInputStream();
}
} catch (IOException e) {
e.printStackTrace();
}
new ServerThread(socket, mInputSteam).start();
}
}
};
thread.start();
}
private void getLocalIpAddress(ServerSocket serverSocket) {
try {
//for(;;)
for (Enumeration<NetworkInterface> mEnumNetwork = NetworkInterface.getNetworkInterfaces(); mEnumNetwork.hasMoreElements();) {
NetworkInterface mNetwork = mEnumNetwork.nextElement();
for (Enumeration<InetAddress> mEnumIpAddress = mNetwork.getInetAddresses(); mEnumIpAddress.hasMoreElements();) {
InetAddress mIpAddress = mEnumIpAddress.nextElement();
String mIp = mIpAddress.getHostAddress().substring(0, 3);
if(mIp.equals("192")){
ip = mIpAddress.getHostAddress(); //获取本地IP
port = serverSocket.getLocalPort(); //获取本地的PORT
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
}
class ServerThread extends Thread {
private Socket socket;
private InputStream inputStream;
private StringBuffer stringBuffer = mStringBuffer;
public ServerThread(Socket socket, InputStream inputStream) {
this.socket = socket;
this.inputStream = inputStream;
}
@Override
public void run() {
int len;
byte[] bytes = new byte[24];
boolean isString = false;
try {
if (inputStream != null) {
//输入流关闭时循环才会停止
//数据读完了,再读是等于0
while ((len = inputStream.read(bytes)) != -1) {
for (int i = 0; i < len; i++) {
if (bytes[i] != '\0') {
stringBuffer.append((char) bytes[i]);
} else {
isString = true;
break;
}
}
if (isString) {
Message msg = handler.obtainMessage();
msg.what = 2;
msg.obj = stringBuffer;
handler.sendMessage(msg);
isString = false;
}
}
}
} catch (IOException e) {
//当这个异常发生时,说明客户端那边的连接已经断开
e.printStackTrace();
try {
inputStream.close();
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
/*当按返回键时,关闭相应的socket资源*/
@Override
public void onBackPressed() {
super.onBackPressed();
try {
mServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端
布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.jie.socketcustomdemo.MainActivity">
<EditText
android:id="@+id/et_ip"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="connect"
android:onClick="connect"
app:layout_constraintTop_toTopOf="@id/et_ip"
app:layout_constraintLeft_toRightOf="@+id/et_ip" />
<EditText
android:id="@+id/et_data"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginLeft="40dp"
app:layout_constraintTop_toBottomOf="@id/et_ip"
app:layout_constraintLeft_toLeftOf="parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="send"
android:onClick="send"
app:layout_constraintTop_toTopOf="@id/et_data"
app:layout_constraintLeft_toRightOf="@+id/et_data" />
</android.support.constraint.ConstraintLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
private EditText mEtIp,mEtData;
private OutputStream mOutputStream = null;
private Socket mSocket = null;
private String ip;
private String data;
private boolean socketStatus = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEtIp = findViewById(R.id.et_ip);
mEtData = findViewById(R.id.et_data);
}
public void connect(View view){
ip = mEtIp.getText().toString();
Toast.makeText(MainActivity.this,""+ip,Toast.LENGTH_SHORT).show();
Thread thread = new Thread(){
@Override
public void run() {
super.run();
if (!socketStatus) {
try {
//连接服务端
mSocket = new Socket(ip,8000);
if(mSocket != null){
socketStatus = true;
}
mOutputStream = mSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
thread.start();
}
public void send(View view){
data = mEtData.getText().toString();
Toast.makeText(MainActivity.this,""+data,Toast.LENGTH_SHORT).show();
if (data != null) {
//在后面加上 '\0' ,是为了在服务端方便我们去解析;
data = data + '\0';
}
Thread thread = new Thread(){
@Override
public void run() {
super.run();
if(socketStatus){
try {
mOutputStream.write(data.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
thread.start();
}
/*当客户端界面返回时,关闭相应的socket资源*/
@Override
public void onBackPressed() {
super.onBackPressed();
/*关闭相应的资源*/
try {
mOutputStream.close();
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意
服务端和客户端都要添加权限
<!--允许应用程序改变网络状态-->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--允许应用程序改变WIFI连接状态-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!--允许应用程序访问有关的网络信息-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--允许应用程序访问WIFI网卡的网络信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允许应用程序完全使用网络-->
<uses-permission android:name="android.permission.INTERNET"/>
效果
客户端
服务端
下一篇: Qt中的TCP服务端和客户端互发消息