TCP编程
首先需要了解TCP的连接过程,然后使用socket编程实现。TCP分为客户端和服务器端编程。下面都会介绍。
但是首先会先介绍下TCP连接的整体概念,其实新手可以先连接整个过程,然后在细致的分析其中各个类的函数怎么用啊,有什么参数啊。当然可以先写一个程序,跑起来,然后在细致的扣含义哈。
在看下面代码之前,建议明白什么java的Thread类如何使用,和I/O通讯哈!
1. TCP建立链接的步骤
1.服务端开放一个port,被动地等待客户端的连接。
2.客户端向服务器端发送连接请求,需要通过该port,然后被动地等待服务器的响应, 通过I/O流与服务端通信 ,当然只有在服务器开启的时候才可能连接上。
3.当客户端向服务端发出连接请求后,并被服务器正确接受并相应后,服务端创建一个sockt实例,并为该实例创建一个新的线程,使用I/O 流与客户端进行通讯
public void client() throws Exception {
Socket socket = new Socket(InetAddress.getLocalHost(), 8090);
// InetAddress.getLocalHost()为客户端请求连接的主机号,此处设置为本地主机,服务进程的端口号是8090
// 主机号和端口号唯一确定了唯一主机上面的唯一进程。
OutputStream os = socket.getOutputStream();
// socket.getOutputStream()获得输出流,通过输出流像主机发送数据。
os.write("黑猫呼叫白猫收到请回复!".getBytes());
socket.shutdownOutput();
// 关闭数据输出,如果不关闭的话服务端并不知道数据传输已经结束还会一直等待。
InputStream is = socket.getInputStream();
int len = 0;
byte[] b = new byte[1024];
while ((len = is.read(b)) != -1) {
String str = new String(b, 0, len);
System.out.println(str);
}
is.close();
os.close();
socket.close();
}
@Test
public void server() throws Exception {
ServerSocket ss = new ServerSocket(8090);
// 给服务端一个端口号8090使得客户端可以连接。
Socket socket = ss.accept();
// 接受客户端的连接
InputStream is = socket.getInputStream();
// 获得客户端的输入流
int len = 0;
byte[] b = new byte[1024];
while ((len = is.read(b)) != -1) {
String str = new String(b, 0, len);
System.out.println(str);
}
OutputStream os = socket.getOutputStream();
// 通过输出流向客户端发送数据。
os.write("黑猫这里是白猫,我已收到你的呼叫!".getBytes());
os.close();
// socket.shutdownOutput();
is.close();
socket.close();
ss.close();
}
2. 服务器处理多客户端请求时
在TCP Socket编程中,客户端有多个,而服务器端只有一个。
- 由客户端TCP向服务器端TCP发送连接请求,服务器端的ServerSocket实例则监听来自客户端的TCP连接请求,并为每个请求创建新的Socket实例。因此要为每个Socket连接开启一个线程。(P14)
- 由于服务端在调用accept()等待客户端的连接请求时会阻塞,直到收到客户端发送的连接请求才会继续往下执行代码。
- 服务器端要同时处理ServerSocket实例和Socket实例,而客户端只需要使用Socket实例。
- 每个Socket实例会关联一个InputStream和OutputStream对象,通过OutputStream来发送数据,并通过从InputStream来接收数据。.
简单来说,使用TCP方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据 。由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。
2.1.TCP客户端创建步骤
- 创建一个Socket实例 指定远程主机的ip和端口,建立一个TCP连接
- 通过I/O流与服务端通信
- 当不需要连接的时候,使用Socket类的close来关闭连接(当通信结束,可以使用Socket的close()方法关闭该客户端连接)
具体代码实现如下:
/**
*
* @param serverIp 服务端 IP
* @param serverPort 服务端端口
* @param msg 发生的消息
* @throws IOException
*/
public static void client(String serverIp, int serverPort, String msg) throws IOException {
String response = null;
//与端口进行连接
Socket socket = new Socket(serverIp, serverPort);
socket.setSoTimeout(5000);
PrintStream out = new PrintStream(socket.getOutputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.println(msg);
try {
response = bufferedReader.readLine();
System.out.println("接收到服务端消息:"+response);
} catch (SocketTimeoutException e) {
System.out.println("连接超时,无响应");
}
if (socket != null) {
//如果构造函数建立起了连接,则关闭套接字,如果没有建立起连接,自然不用关闭
socket.close(); //只关闭socket,其关联的输入输出流也会被关闭
}
}
2.2 TCP服务端创建步骤:
创建一个ServerSocket实例并指定本地端口,用来监听客户端在该端口发送的TCP连接请求。当接收客户端TCP 请求后
- 调用ServerSocket的accept()方法以获取客户端连接,并通过其返回值创建一个Socket实例
- 为返回的Socket实例开启新的线程,并使用Socket实例的I/O流与客户端通信
- 当连接终止后,调用ServerSocket close 方法,关闭服务端
具体实现代码:
/**
* 这个类主要是为了用来创建Sockt 实例
*/
public class TcpServerThread implements Runnable {
private Socket socketClient = null;
String responseToClient = "你好客户端";
public TcpServerThread(Socket socketClient) {
this.socketClient = socketClient;
}
public void run() {
try {
//获取Socket的输出流,用来向客户端发送数据
PrintStream out = new PrintStream(socketClient.getOutputStream());
//获取Socket的输入流,用来接收从客户端发送过来的数据
BufferedReader buf = new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
boolean flag = true;
while (flag) {
//接收从客户端发送过来的数据
String str = buf.readLine();
if (str == null || "".equals(str)) {
flag = false;
} else {
//将接收到的字符串前面加上echo,发送到对应的客户端
System.out.println("接受到客户端消息客户端消息:" + str);
out.println(":" + responseToClient);
}
}
out.close();
socketClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param port 服务器端口
* @throws Exception
*/
public static void tcpServer(int port)throws Exception{
ServerSocket serverSocket =new ServerSocket(port);
Socket socketClient=null;
boolean flag=true;
while (flag){
socketClient=serverSocket.accept();
System.out.println("与客户端连接成功");
new Thread(new TcpServerThread(socketClient)).start();
}
serverSocket.close();
}
当然跑代码的时候,肯定是先跑server,否则client的连接肯定会出错哈,然后一定注意其中异常的抛出,还有使用完成后,需要对socket进行关闭什么的问题。