Android网络之简单服务器与客户端双向接收

这里我们通过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中添加网络权限:

    
    

大家请注意代码中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结束符才会返回,否则程序就一直阻塞在这里不会向下运行。


你可能感兴趣的:(Android,Java)