基于TCP协议的通信(基于Java语言)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/carson0408/article/details/83830458

        端与端通信,经常由客户端和服务端两者组成,其中客户端发送请求给服务端,而服务端则响应请求。这两者的通信可以通过Socket来实现两端的数据传输。其中Java自带的Socket类可以创建客户端socket,而ServerSocket可以创建一个服务端Socket。

1.服务端-客户端的通信创建以及工作流程

       由于Socket是两台主机之间的一个连接,Socket简化了网络的底层细节,比如传输数据过程中的错误检测、包大小、包分解、包重传、网络地址等,简化了网络编程的部分工作。以下分别讲解服务端、客户端创建以及工作流程

1.1.服务端Socket的创建流程

1.使用一个ServerSocket()构造函数在一个特定端口创建一个新的ServerSocket。

2.ServerSocket使用其accept()方法监听这个端口的入站连接。accept()方法会一直阻塞,直到一个客户端尝试建立连接,此时accept(0将返回一个连接客户端和服务器的socket对象。

3.根据服务器的类型,会调用socket的getInputStream()方法或getOutputStream()方法,或者两者都调用,以获得与客户端通信的输入和输出流。

4.服务端和客户端根据已协商好的协议进行交互,直到关闭连接。

5.服务端关闭连接

6.服务器返回步骤2,等待下一次连接。

1.2.客户端Socket的创建流程

1.使用一个Socket构造函数创建一个连接远程ip,特定端口的主机的socket。与服务端建立通信。

2.调用socket的getInputStream()方法和getOutputStream()方法,以获得与服务端通信的输入输出流。

3.通过将输出流写入socket,向服务端发送请求;并通过获取socket的输入流返回服务端的响应。

4.关闭socket。

2.通信过程中常用的一些类

        Java中JDK提供了许多API实现网络编程,以下便是几个常用的类。

2.1.Socket类

         一般我们都是通过Socket类的构造函数创建Socket,而一个socket对象需要一个远程ip和对应端口两个参数才能确定。因此有如下构造函数:

Socket(InetAddress/String remoteAddress,int port):创建连接到指定远程主机、远程端口的socket,该构造器没有指定本地地址、本地端口,默认使用本地主机的IP地址,默认使用系统动态分配的端口。

Socket(InetAddress/String remoteAddress,int port,InetAddress localAddr,int localPort):创建连接到指定远程主机、远程端口的socket,并指定本地IP地址和本地端口,适用于本地主机有多个IP地址的情形。

2.2.ServerSocket类

        ServerSocket类用于服务端创建ServerSocket对象,建立监听连接。具有以下构造函数:

ServerSocket(int port):用指定的端口port来创建一个ServerSocket。该端口应该有一个有效的端口整数值,即0~65535.

ServerSocket(int port,int backlog):增加一个用来改变连接队列长度的参数backlog。

ServerSocket(int port,int backlog,InetAddress localAddr):在机器存在多个IP地址的情况下,允许通过localAddr参数来指定将ServerSocket绑定到指定的IP地址。

        一般服务端与客户端相互连接之后,需要用accept方法用于监听来自客户端的Socket连接。如果没有连接,将一直处于等待状态,如果有连接,则返回socket对象。

Socket accept():如果接收到一个客户端Socket的连接请求,该方法将返回一个与客户端Socket对应的Socket,否则一直处于等待状态,线程也被阻塞。

3.用例

        该例子的目标是在服务端实现字符串的翻转。即客户端通过在控制台写入一行字符串,然后发送请求给服务端,服务端进行翻转,然后返回给客户端输出。由于客户端与服务端都在本地,所以客户端连接的远程ip为本地ip即可。

客户端:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {
	public static BufferedReader bufferedReader = null;
	public static PrintStream pStream = null;
	public static BufferedReader keyIn= null;//用于键盘输入
	public static void main(String[] args) throws UnknownHostException, IOException {
		// TODO Auto-generated method stub
		
		keyIn = new BufferedReader(new InputStreamReader(System.in));
		//创建socket连接,连接对应ip指定port
		Socket socket = new Socket("127.0.0.1", 3002);
		String in = keyIn.readLine();//获取键盘输入
		pStream = new PrintStream(socket.getOutputStream());
		pStream.println(in);//将请求写入socket发送
		bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//获取输入流,即获取服务端响应。
		String anString = bufferedReader.readLine();
		if(anString==null) {
			System.out.println("网络通信出现故障");
		}
		else {
			System.out.println("服务端响应结果:"+anString);
		}
		//将资源关闭
		pStream.close();
		bufferedReader.close();
		keyIn.close();
		socket.close();
		
	}

}

服务端:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	public static BufferedReader bufferedReader = null;
	public static PrintStream pStream = null;
	public static String reverse(String line) {
		return new StringBuilder(line).reverse().toString();
	}

	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		//建立监听的serversocket
		ServerSocket serverSocket = new ServerSocket(3002);
			
		//利用死循环来接收客户端的请求
		while(true) {
			Socket socket = serverSocket.accept();
			//获取客户端请求
			bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			//输出流,用于写入服务端响应
			pStream = new PrintStream(socket.getOutputStream());
			String line = bufferedReader.readLine();
			String out = null;
			if(line!=null) {
				out = reverse(line);
			}
			if(out==null) {
				pStream.println("该请求无法实现!");
			}
			else {
				pStream.println("请求响应成功:"+out);
			}
			//关闭资源
			pStream.close();
			bufferedReader.close();
			socket.close();
		}
	

	}

}

先启动服务端,打开监听,等待客户端请求发送,然后启动服务端,并在控制台输入一行字符串,便可获取响应。

        这个简单例子说明了socket作为客户端和服务端通信的虚拟链路的连接。说明了如何获取输入,发送请求,以及获取响应的过程。 

猜你喜欢

转载自blog.csdn.net/carson0408/article/details/83830458