解析服务器端代码
代码是放在app/lib下的src下的main/java,而与之前放在app/src/main下路径不同
Main函数
Main函数里只放着创建MyServer类的一行
public static void main(String args[]){
new MyServer();
}
MyServer构造函数
1.获取本机IP地址
//获取本机IP地址
InetAddress addr = InetAddress.getLocalHost();
System.out.println("local host:" + addr);
2.创建serverSocket(创建服务器套接字并绑定到一个端口上)
//创建server socket
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("listen port 9999");
3.accept方法监听等待
//等待客户端连接
while(true){
System.out.println("waiting client connect");
//从连接请求队列中取出一个客户的连接请求,然后创建与客户连接的Socket对象,并将它返回
// 如果队列中没有连接请求,accept()方法就会一直等待,直到接收到了连接请求才返回
Socket socket = serverSocket.accept();
//连接成功,返回socket对象
System.out.println("accept client connect" + socket);
new Thread(new Service(socket)).start();
}
4.监听成功,创建线程进行通信(上一步while循环内最后一行)
创建线程进行通信
- 线程构造函数内,new数据传输通道
class Service implements Runnable{
private Socket socket;
private BufferedReader in = null;
public Service(Socket socket){
this.socket = socket;
try{
//InputStreamReader把字节流转化成字符流
//BufferedReader用于读取字符流。它继承自Reader类,提供了按行读取文件的功能
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}catch (IOException ex){
ex.printStackTrace();
}
}
- 重写的run函数内,用一个while来不断读入客户端传来的流(用BufferedReader)
@Override
public void run() {
System.out.println("wait client message " );
try {
while ((content = in.readLine()) != null) {
//从socket连接读取到bye标识客户端发出断开连接请求
if(content.equals("bye")){
System.out.println("disconnect from client,close socket");
//关闭socket输入输出流
socket.shutdownInput();
socket.shutdownOutput();
socket.close(); //关闭socket连接
break;
}else {
//从socket连接读取到的不是断开连接请求,则像客户端发信息
this.sendMessge(socket);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
- 如何sendMessage:用PrintWriter
public void sendMessge(Socket socket) {
PrintWriter pout = null;
try{
String message = "hello,client!";
System.out.println("messge to client:" + message);
//OutputStreamWriter:将字符流转换为字节流
//BufferedWriter:是缓冲字符输出流
//PrintWriter:字符类型的打印输出流
pout = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(),"utf-8")),true);
//利用输出流输出数据
pout.println(message);
}catch (IOException ex){
ex.printStackTrace();
}
}
解析客户端代码
1.与服务器的连接
NetConn netConn = new NetConn(handler);
2.与服务器的信息交流
其中的writer在与服务器进行连接会把它进行赋值,它是获得了socket输出流的PrintWriter,把信息给到服务器。(注:接收服务器的信息是在netConn线程的run方法里用了一个while)
new Thread(){
@Override
public void run(){
Log.i(TAG, "send message to server");
writer.println("hello,server");
}
}.start();
NetConn是一个线程
在重写的 run 方法里
1.创建socket并连接对象
//创建socket对象
socket = new Socket();
//connect,要保证服务器已启动
socket.connect(new InetSocketAddress
("10.0.2.2",9999),5000);
2.获取socket的输入输出流
//获取socket输入输出流
in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
writer = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream(),"utf-8")),true);
Log.i(TAG,"connect to server");
3.再建一个线程,接收服务器的数据
//接收服务器返回的数据
Thread receiveServerMsg = new Thread(){
@Override
public void run(){
String fromserver = null;
try{
while((fromserver = in.readLine())!=null)
{
//发送消息给UI线程
Message msg = new Message();
msg.what = 1;
msg.obj = fromserver;
toClientHandler.sendMessage(msg);
}
}catch (IOException ex){
ex.printStackTrace();
}
}
};
感觉hander像个快递员???把在服务器接收数据线程里,接收到的东西,打包成message,通过sendMessage函数,发给UI线程(就是那些Activity),进行相应操作。
以下是MainActivity内的Handler
handler = new Handler(Looper.getMainLooper()){
//当数据处理子线程更新数据后发送消息给UI线程,UI线程更新UI
@Override
public void handleMessage(Message msg){
if(msg.what == 1){
txt.setText(msg.obj.toString());
}
}
};