温习旧知识,巩固基础,同时还能有新的收货。
古人云:温故而知新,可以为师矣。
那就分享出来一起学习吧。
服务端,纯Java实现:
public class EchoServer {
public static void main(String args[]) {
try {
ServerSocket serverSocket = new ServerSocket(8999);
while (true) { //直接在主线程做了,不另起线程了
Socket socket = serverSocket.accept();
System.out.println("connected from:" + socket.getInetAddress());
new SocketThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class SocketThread extends Thread {
private Socket mSocket;
public SocketThread(Socket socket) {
this.mSocket = socket;
}
@Override
public void run() {
BufferedReader br = null;
PrintWriter pw = null;
try {
br = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
pw = new PrintWriter(new OutputStreamWriter(mSocket.getOutputStream()));
String line;
while (true) {
line = br.readLine();
System.out.println("received:" + line + " from:" + mSocket.getInetAddress());
String result = "response: " + line + "\n"; //我们用的都是readLine方法读取,所以加入换行符,代表结尾
pw.print(result);
pw.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (pw != null) {
pw.close();
}
if (mSocket != null && !mSocket.isClosed()) {
try {
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
Android客户端:
public class MainActivity extends AppCompatActivity {
private EditText mIpEt;
private EditText mPortEt;
private Button mConnBtn;
private TextView mScreenTv;
private EditText mInputEt;
private Button mSendBtn;
private SocketThread mSocketThread;
private static Handler mMainHandler;
private static final int MSG_CONNECT = 0x001;
private static final int MSG_RECEIVE = 0x002;
private static final String DATA_RECEIVE = "data_receive";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIpEt = findViewById(R.id.main_ip_et);
mPortEt = findViewById(R.id.main_port_et);
mConnBtn = findViewById(R.id.main_connect_btn);
mScreenTv = findViewById(R.id.main_screen_tv);
mInputEt = findViewById(R.id.main_input_et);
mSendBtn = findViewById(R.id.main_send_btn);
// defalut value. Change it to your own server ip
mIpEt.setText("192.168.1.1");
mPortEt.setText("8999");
mConnBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String ip = mIpEt.getText().toString();
String port = mPortEt.getText().toString();
if (TextUtils.isEmpty(ip) || TextUtils.isEmpty(port)) {
Toast.makeText(MainActivity.this, "ip or port is null", Toast.LENGTH_SHORT).show();
} else {
connectToServer(ip, Integer.valueOf(port));
}
}
});
mSendBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String data = mInputEt.getText().toString();
if (!TextUtils.isEmpty(data)) {
mSocketThread.sendMsgToServer(data + "\n"); //我们用的都是readLine方法读取,所以加入换行符,代表结尾
}
}
});
// TODO handler may cause memory leaks
mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_CONNECT:
Toast.makeText(MainActivity.this, "Connect to Server Success", Toast.LENGTH_SHORT).show();
mConnBtn.setText("Connected");
mConnBtn.setEnabled(false);
break;
case MSG_RECEIVE:
Bundle data = msg.getData();
String dataStr = data.getString(DATA_RECEIVE);
CharSequence originData = mScreenTv.getText();
String result = originData + "\n" + dataStr;
mScreenTv.setText(result);
break;
}
}
};
}
private void connectToServer(String ip, int port) {
mSocketThread = new SocketThread(ip, port);
mSocketThread.start();
}
// 程序简单,直接写静态内部类来实现了
private static class SocketThread extends Thread {
private Socket mSocket;
private String mIp;
private int mPort;
private InputStream mInputStream;
private BufferedReader mBufferedReader;
private PrintWriter mPrintWriter;
public SocketThread(String ip, int port) {
this.mIp = ip;
this.mPort = port;
}
@Override
public void run() {
try {
mSocket = new Socket(mIp, mPort);
mMainHandler.sendEmptyMessage(MSG_CONNECT);
// init i/o stream
mInputStream = mSocket.getInputStream();
mBufferedReader = new BufferedReader(new InputStreamReader(mInputStream));
OutputStream outputStream = mSocket.getOutputStream();
mPrintWriter = new PrintWriter(outputStream);
String line;
while (true) {
line = mBufferedReader.readLine();
Message message = mMainHandler.obtainMessage();
message.what = MSG_RECEIVE;
Bundle data = new Bundle();
data.putString(DATA_RECEIVE, line);
message.setData(data);
mMainHandler.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (mBufferedReader != null) {
try {
mBufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (mInputStream != null) {
try {
mInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (mPrintWriter != null) {
mPrintWriter.close();
}
if (mSocket != null && !mSocket.isClosed()) {
try {
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void sendMsgToServer(final String data) {
new Thread(new Runnable() {
@Override
public void run() {
mPrintWriter.print(data);
mPrintWriter.flush();
}
}).start();
}
}
}
MainActivity的布局文件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="15dp">
<EditText
android:id="@+id/main_ip_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="ip address"/>
<EditText
android:id="@+id/main_port_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="port"
android:inputType="number"/>
<Button
android:id="@+id/main_connect_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Connect"/>
<EditText
android:id="@+id/main_input_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="message to server"/>
<Button
android:id="@+id/main_send_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Send"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp">
<TextView
android:id="@+id/main_screen_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="received message will be shown here"/>
</ScrollView>
</LinearLayout>
最后别忘了Android客户端里声明网络权限。
其他就没有什么特别要注意的点了,直接跑起来吧~
客户端运行
服务端日志