一起Talk Android吧(第三百二十四回:Android中网络通信之TCP通信模型一)

各位看官们,大家好,上一回中咱们说的是Android中网络通信之TCP客户端的例子,这一回中咱们说的例子是网络通信之TCP通信模型。闲话休提,言归正转。让我们一起Talk Android吧!

看官们,我们在上一回中通过具体的代码演示了如何进行TCP通信,不过这种通信属于最基本的通信,在实际项目中还需要添加通信模型。本章回中介绍迭代模型,也就是多个客户端同时与一个服务器进行通信。下面是该模型的示意图:

一起Talk Android吧(第三百二十四回:Android中网络通信之TCP通信模型一)_第1张图片

只有文字和图像不足以了解迭代模型,下面我们通过文字结合代码的方法来介绍迭代模型:

服务端演示

我们先定义T8Server2类,并且定义该类的构造方法,构造方法中包含一个参数表示服务器的端口,通过构造方法可以创建一个服务器对象。

我们在类中定义了acceptConnectRequest()方法,该方法封装了accept()方法,主要用来接受客户端发起的连接请求并且与客户端建立连接。

我们在类中定义了disconnectClient()方法,该方法封装了close()方法,主要用来断开服务端和客户端之间的TCP连接。

我们在类中定义传输数据的方法sendDataToClient()和getDataFromClient(),这两个方法使用了IO流来发送和接收数据,发送和接收数据时使用了字节流和字符流两种不同的方法,因此部分代码有注释,其中的细节我们就不详细了,大家可以参考下面的代码。

这些内容和上一章回的完全相同,不同之处有三点:类名、每次都获取输入流、使用字符流而不是字节流读取socket中的数据。如果大家对上一章回的内容比较熟悉,只关注这三个细节方面的差异就可以。

此外,上一章回中的代码注释把字节流和字符流写反了,在这里做个修正。

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.PrintStream;

public class T8Server2 {
    private Socket mSocket;
    private ServerSocket mServerSocket;
    private int mPort;
    private InputStream mSocketInputStream;
    private OutputStream mSocketOutputStream;

    public T8Server2 (int port) {
    	mPort = port;
    	try {
    		mServerSocket = new ServerSocket(mPort);
    	}catch(Exception e) {
        	e.printStackTrace();
    	}
    }

    public void acceptConnectRequest() {
    	if(mServerSocket != null) {
    		try {
                if(!mServerSocket.isClosed()) {
        			mSocket = mServerSocket.accept();
        			System.out.println("Server accept the request of Client");
                }
    		}catch(Exception e) {
    	    	e.printStackTrace();
    		}
    	}
    }

    public void disconnectClient() {
    	if(mServerSocket!= null && !mServerSocket.isClosed()) {
    		try {
    			if(mSocketInputStream != null)
    				mSocketInputStream.close();

    			if(mSocketOutputStream != null)
    				mSocketOutputStream.close();

                mServerSocket.close();
                mServerSocket = null;
    		}catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

    public void sendDataToClient(String data) {
    	PrintStream printStream = null;
    	try {
    		if(mSocketOutputStream == null) {
    			mSocketOutputStream = mSocket.getOutputStream();
    		}

    		if(printStream == null) {
    			printStream = new PrintStream(mSocketOutputStream);
    		}

    		printStream.println(data);
    		// mSocketOutputStream.write(data.getBytes());
    		// mSocketOutputStream.flush();

    	}catch (IOException e) {
    			e.printStackTrace();
    	}
    }

     public String getDataFromClient() {
     	String data = null;
     	BufferedReader bufferedReader = null;
     	StringBuilder strTemp = new StringBuilder();
     	byte [] bytes = new byte[1024];
        char [] charByte = new char[512];

    	try {
    		if(mSocket != null && mSocket.isConnected()) {
    			mSocketInputStream = mSocket.getInputStream();

            //get data by character stream
                new InputStreamReader(mSocketInputStream).read(charByte);
                data = String.valueOf(charByte);
            }
            //get data by byte stream
    		// if(bufferedReader == null) {
    		// 	bufferedReader = new BufferedReader(new InputStreamReader(mSocketInputStream));
    		// }

    		// data = bufferedReader.readLine();
    	}catch (IOException e) {
    			e.printStackTrace();
    	}

    	return data;
    }

}

客户端演示

我们先定义T8Client2类,并且定义该类的构造方法,构造方法中包含三个参数,分别表示服务器的IP地址、端口和客户端的ID,通过构造方法可以创建一个客户端对象。

我们在类中定义了connectServer()方法,该方法封装了connect()方法,主要用来向服务端发起连接请求。

我们在类中定义了disconnectServer()方法,该方法封装了close()方法,主要用来断开服务端和客户端之间的TCP连接。

我们在类中定义传输数据的方法sendDataToServer()和getDataFromSever(),这两个方法使用了IO流来发送和接收数据,发送和接收数据时使用了字节流和字符流两种不同的方法,因此部分代码有注释,其中的细节我们就不详细了,大家可以参考下面的代码。

最后我们添加一个方法用来启动线程,在程序中做“连接服务器"和"发送数据到服务器"的操作;

这些内容和上一章回的内容大部分相同,不同之处有两点:构造方法多了一个参数;启动线程的方法是新添加的。

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.PrintStream;

public class T8Client2 {
    private String strAddress;
    private Socket mSocket;
    private String mHost;
    private int mPort;
    private String mID;
    private InetAddress remoteAddr;
    private SocketAddress mSocketAddress;
    private InputStream mSocketInputStream;
    private OutputStream mSocketOutputStream;
    private Thread mThead;

    public T8Client2 (String addr, int port,String id) {
    	try {
    		strAddress = addr;
    		mPort = port;
            mID =id;
            remoteAddr = InetAddress.getByName(strAddress);
            mSocketAddress = new InetSocketAddress(remoteAddr,mPort);
            mSocketOutputStream = null;
            mSocketInputStream = null;
        } catch(Exception e) {
        	e.printStackTrace();
        }

        try {
        	mSocket = new Socket();
        }catch(Exception e) {
        	e.printStackTrace();
        }
    }

    public void connectServer() {
    	int timeOut = 5000;
    	try {
    		mSocket.connect(mSocketAddress,timeOut);
    		System.out.println("Client connect to Server successfully");
    	}catch (Exception e) {
    		e.printStackTrace();
    	}
    }

    public void disconnectServer() {
    	if(mSocket != null && mSocket.isConnected()) {
    		try {
    			if(mSocketInputStream != null)
    				mSocketInputStream.close();

    			if(mSocketOutputStream != null)
    				mSocketOutputStream.close();

        		mSocket.close();
    		}catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }

    public boolean isConnected() {
        boolean result = false;

        if(mSocket != null) {
            if( mSocket.isConnected())
                result = true;
        }

        return result;
    }


    public void sendDataToServer(String data) {
    	PrintStream printStream = null;
    	try {
    		if(mSocketOutputStream == null) {
    			mSocketOutputStream = mSocket.getOutputStream();
    		}

    		if(printStream == null) {
    			printStream = new PrintStream(mSocketOutputStream);
    		}

    		// printStream.println(data);
    		mSocketOutputStream.write(data.getBytes());
    		// mSocketOutputStream.flush();

    	}catch (IOException e) {
    			e.printStackTrace();
    	}
    }

     public String getDataFromSever() {
     	String data = null;
     	BufferedReader bufferedReader = null;
     	StringBuilder strTemp = new StringBuilder();
     	byte [] bytes = new byte[512];

    	try {
    		if(mSocketInputStream == null) {
    			mSocketInputStream = mSocket.getInputStream();
    		}

    		mSocketInputStream.read(bytes);
    		if(bufferedReader == null) {
    			bufferedReader = new BufferedReader(new InputStreamReader(mSocketInputStream));
    		}

    		data = bufferedReader.readLine();
    	}catch (IOException e) {
    			e.printStackTrace();
    	}

    	// for(byte item : bytes) {
    	// 	strTemp.append(String.format("%s", item));
    	// }

    	// data = strTemp.toString();

    	return data;
    }


    public void startRunning() {
        mThead = new Thread(new Runnable () {
            @Override
            public void run() {
                connectServer();
                sendDataToServer(mID);
            }
        });

        mThead.start();
    }

    
}

TCP通信演示

我们创建一个包含main方法的类,用它来当作控制TCP通信的主程序。在main方法中先创建服对象。因为TCP通信过程中会阻塞主线程,也就是main方法所在在线程,所以我们创建了一个子线程,用来表示服务端。在服务端线程中主要是监听客户端发来的连接请求,在接受连接请求后接收客户端发来的数据,接收完最后一条数据后关闭TCP连接。

接着创建五个客户端对象,并且添加到数组中,接着依次调用客户端的startRunning()方法来启动线程,线程启动后,客户端会向服务端发起连接并且发送数据到服务端。

这里一共有五个客户端并且每个客户端都对应一个线程,这相当于有五个客户端同时在和服务器进行TCP通信。为了方便演示,我们在启动每个客户端的线程之间添加了延时。

我们在客户端向服务端发送的数据是客户端的ID,比如:“Client3”,在程序运行时可以看到。注意需要先启动服务端线程后再启动客户端线程。下面是该类的代码,请大家参考:


import java.util.ArrayList;

public class TCPEx2 {

	public static void main(String args[]) {
		String serverAddress = "127.0.0.1";
		int serverPort = 8009;
		T8Server2 mServer;
		T8Client2 mClient;


		Thread mServerThread;
		Thread mClientThread;

		ArrayList<T8Client2> clientGroup = new ArrayList<T8Client2>();

		mServer = new T8Server2(serverPort);
		mServerThread = new Thread( new Runnable() {
			@Override
            public void run() {
            	boolean flag = true;
            	String data = null;

				while(flag) {
					if(mServer != null) 
						mServer.acceptConnectRequest();

					data = mServer.getDataFromClient();
					System.out.println("---> Server get data < "+data+" > form Client.");
					System.out.println();

					if(data.contains("5")) {
						flag = false;
					}
				}

				System.out.println("---> server stop running...");
				mServer.disconnectClient();
            }
		});

		mServerThread.start();


		for(int i=0; i<5; i++) {
			String id = String.valueOf(i+1);
			id = "Client"+id;
			mClient = new T8Client2(serverAddress,serverPort,id);
			clientGroup.add(mClient);
			mClient = null;
		}

		for(int i=0; i<clientGroup.size();i++) {
			mClient = clientGroup.get(i);

			System.out.println("<-- Client["+i+"] send request to Server.");
			mClient.startRunning();
			mClient = null;

			try {
	            Thread.sleep(100);
	        } catch(InterruptedException e) {
	    	    e.printStackTrace(); 
	        } 
		}

	}

}

在控制台中编译并且运行这三个类,可以得到以下结果:

$ javac T8Client2.java T8Server2.java TCPEx2.java

$ java TCPEx2
<-- Client[0] send request to Server.
Client connect to Server successfully
Server accept the request of Client
---> Server get data < Client1 > form Client.

<-- Client[1] send request to Server.
Client connect to Server successfully
Server accept the request of Client
---> Server get data < Client2 > form Client.

<-- Client[2] send request to Server.
Client connect to Server successfully
Server accept the request of Client
---> Server get data < Client3 > form Client.

<-- Client[3] send request to Server.
Client connect to Server successfully
Server accept the request of Client
---> Server get data < Client4 > form Client.

<-- Client[4] send request to Server.
Client connect to Server successfully
Server accept the request of Client
---> Server get data < Client5 > form Client.

---> server stop running...

看官们,关于Android中网络通信之TCP通信模型的例子咱们就介绍到这里,欲知后面还有什么例子,且听下回分解!

你可能感兴趣的:(一起Talk,Android吧,Socket,Java,TCP)