这里我们通过Socket实现功能;
我们在PC机端用Java编写一个简单的服务器,向客户端发送数据同时接收客户端发送过来的数据并打印出来。同理,我们的Android APP作为客户端,同样向服务端发送数据,并且接收其发送来的数据,并通过TextView显示出来。
首先作为服务器端的代码:
package com.socket.myu;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class NetServer {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
ServerSocket ss = new ServerSocket(55554);
System.out.println(ss.getLocalSocketAddress());
while (true) {
Socket socket = ss.accept();
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
System.out.println(bufferedReader.readLine());
OutputStream outputStream = socket.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write("myu\n");
bufferedWriter.flush();
System.out.println("-----------------");
inputStream.close();
outputStream.close();
socket.close();
}
}
}
这段代码表示我们在55554端口中进行网络监听。
初学者可能会认为这里一直在进行while循环会导致进程一直占有CPU。这里不用担心,因为accept()方法会导致进程阻塞。什么意思呢?假如我们正在这个端口监听网络,但此时并没有任何客户端请求这个端口。此时进程就会进入阻塞状态(进程有三态),并让出CPU资源。
appcet()方法有什么作用呢?其作用是等待客户端连接XXX端口。
这里又引出另外一个知识点。JAVA I/O知识点中,InputStream和OutputStream表示的输入流和输出流(其都是以内存为中心点),都是字节流。而InputStreamReader、BufferedReader这些都是字符流。在JAVA中程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。
Reader类(字符流)的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1
inputStream类(字节流)的read()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用0-255来表示的值就得用字符流来读取!比如说汉字.
所以输入或输出时,我们通常需要把字节流转换成字符流这点需要注意。
Android客户端APP:
package com.example.netserver2android;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView1);
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
}
public class MyThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
try {
Log.v("123", "ready socket !!!");
Socket socket = new Socket("192.168.1.147", 55554);
Log.v("123", "-->" + socket.getInetAddress().getHostAddress());
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
outputStream);
BufferedWriter bufferedWriter = new BufferedWriter(
outputStreamWriter);
bufferedWriter.write("Hello world!!!\n");
bufferedWriter.flush();
InputStreamReader inputStreamReader = new InputStreamReader(
inputStream);
BufferedReader bufferedReader = new BufferedReader(
inputStreamReader);
String test;
test = bufferedReader.readLine();
textView.setText(test);
outputStream.close();
inputStream.close();
socket.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
同时,在AndroidManifest.xmk中添加网络权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
大家请注意代码中bufferedWriter.write("Hello world!!!\n");这句话。
这里之前我犯了一个致命的问题导致服务器端一直停滞在System.out.println(bufferedReader.readLine());。我之前是bufferedWriter.write("Hello world!!!");这样写的。
经过查询得知readLine()也是阻塞的。
String java.io.BufferedReader.readLine() throws IOException
Returns the next line of text available from this reader. A line is represented by zero or more characters followed by '\n', '\r', "\r\n" or the end of the reader. The string does not include the newline sequence.
Returns:
the contents of the line or null if no characters were read before the end of the reader has been reached.
Throws:
IOException - if this reader is closed or some other I/O error occurs.
这段是readLine()方法的解释,可以看到该方法是读取一行数据直到遇到\n、\r、\r\n结束符才会返回,否则程序就一直阻塞在这里不会向下运行。