TCP协议-如何实现客户端与服务器端的通信(点对点间的通信)

 一、网络编程

        在Java中,可以通过InetAddress类的静态方法getLocalHost()来获取本地主机的IP地址

代码如下:

package com.ztt.Demo01;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Test01 {
	public static void main(String[] args) {
		try {
			//获取本地主机的网络地址(InetAddress对象)
			//InetAddress netAddr=InetAddress.getLocalHost();
			
			//获取指定域名主机的网络地址(InetAddress对象)
			InetAddress[] netAddrArray=InetAddress.getAllByName("www.taobao.com");
			
			for(InetAddress netAddr:netAddrArray) {
				System.out.println("主机名称:"+netAddr.getHostName());
				System.out.println("主机IP地址:"+netAddr.getHostAddress());
			}
		} catch (UnknownHostException e) {
			
			e.printStackTrace();
		}
	}

}

        在Java中,如果需要测试网络是否通畅,可以使用Runtime对象的exec()执行ping命令

代码如下:

package com.ztt.Demo01;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

//心跳网络检测(简陋版)
public class Test02 {
	public static void main(String[] args) {
		try {
			//获取当前应用程序的"运行时"
			Runtime rt=Runtime.getRuntime();
			
			//调用exec()方法,向操作系统发送要执行的命令
			Process process=rt.exec("ping 192.168.199.102");
			
			//通过process进程对象的输入流,"读取"执行结果
			InputStream in=process.getInputStream();//字节流
			InputStreamReader streamReader=new InputStreamReader(in,"gbk");//转换流
			BufferedReader reader=new BufferedReader(streamReader);//缓冲区字符流
			
			String line=null;
			while((line=reader.readLine())!=null) {
				System.out.println(line);
			}
			
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
		
	}

}

二、 TCP编程

1.编写服务器端程序

        Java标准库提供了ServerSocket来实现对指定IP和指定端口的监听

1.1.Socket的用法

Socket是一种网络通信的编程接口,通过TCP/IP协议将数据传输到网络上

在使用Socket进行编程时,其本质就是俩个进程之间的网络通信。分别为服务器端和客户端,其中服务器端会监听某个指定的端口,客户端连接服务器端的IP地址和指定端口

  • 服务端首先启动,等待客户连接
  • 创建服务端Socket对象,监听1011端口
  • 服务端启动,并进入"等待状态"(等待某一个客户端的连接),当如果没有客户端连接时,accept()处于等待阻塞状态;如果发现客户端连接时,accept()返回当前正在连接的客户端Socket
  • 服务端读取来自客户端的一条信息

 代码如下:

package com.ztt.tcp.Demo01;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

//serverSocket
//Socket
//服务端:首先启动,等待客户端连接
public class Server {
	public static void main(String[] args) {
		//
		try (ServerSocket serverSocket = new ServerSocket(8848)) {
			
			while(true) {
				//服务端启动,并进入"等待状态"(等待某一个客户端的连接)
				//当如果没有客户端连接时,accept()处于等待阻塞状态
				//当如果发现客户端连接时,accept()返回当前正在连接的客户端Socket
				Socket clientSocket=serverSocket.accept();
				
				InetAddress clientNetAddress=clientSocket.getInetAddress();
				System.out.printf("客户端%s正在连接服务器......\n",clientNetAddress.getHostAddress());
				
				//服务器端读取来自客户端的一条消息
				BufferedReader reader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
				
				String message=reader.readLine();
				System.out.printf("客户端%s说:%s\n",clientNetAddress.getHostAddress(),message);
			}
			
			//服务端启动,并进入"等待状态"(等待某一个客户端的连接)
			
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
	}

}

2.编写客户端程序 

  • 客户端:在服务器启动后,向服务端发送一个连接的请求
  • 客户端Socket对象,连接指定IP和端口
  • 连接成功后就可以向服务端发送信息了

代码如下:

package com.ztt.tcp.Demo01;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;

//客户端:在服务器启动后,向服务器发送一个连接请求
public class Client {
	public static void main(String[] args) {
		//创建客户端Socket对象,连接指定IP和端口
		try (Socket clientSocket = new Socket("192.168.199.102",8848)) {
			
			//客户端向服务器发送一条信息(输出流)
			BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
			writer.write("哈哈哈哈~~");//写入缓冲区(内存)
			writer.flush();//清发送至网络空缓冲区,
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

三、实例:超简陋版人工AI对答程序 

1.服务器端程序

1.1步骤 
  • 在类中首先定义了一个静态的HashMap对象map,用于存储问题与答案的对应关系。
  • 在main方法中,首先创建一个ServerSocket对象serverSocket,并绑定到端口 8848,用于监听客户端的连接请求。
  • 进入一个无限循环,使用serverSocket.accept()方法等待并接受客户端的连接请求,连接成功后会返回一个Socket对象clientSocket。
  • 获取连接的客户端的 IP 地址,并存储在clientIp变量中。
  • 然后分别创建BufferedReader对象reader和BufferedWriter对象writer,用于读取客户端发送的问题和向客户端发送问题的答案。
  • 使用reader.readLine()方法读取客户端发送的问题,并将其存储在question变量中。如果读取到的问题为空或者长度为 0,则跳过本次循环。
  • 根据读取到的问题,在map中查找对应的答案,并将其存储在answer变量中。如果在map中未找到对应的问题,将answer设置为“对不起,我不知道您在说什么?”。
  • 使用writer.write()方法将问题的答案发送给客户端。
  • 如果在上述的输入输出操作或网络连接过程中发生IOException异常,将打印异常的堆栈跟踪信息,用于错误排查和调试。

代码如下:

package com.ztt.tcp.Demo01;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
//人工智障对答程序【服务器】
public class AIzzServer {
	private static HashMap<String,String> map=new HashMap<String,String>();
	static {
		map.put("你好", "你好呀,孙子");
		map.put("hi", "hello,孙子");
		map.put("hello", "hi,孙子");
		map.put("吃了吗", "没呢,孙子");
		map.put("很高兴认识你", "我也是哦");
	}
	
	public static void main(String[] args) {
		try (ServerSocket serverSocket = new ServerSocket(8848)) {
			
			while(true) {
				Socket clientSocket=serverSocket.accept();
				String clientIp=clientSocket.getInetAddress().getHostAddress();
				
				//输入流:读取客户端发送的"问题"
				//输出流:发送问题的答案给客户端
				try(BufferedReader reader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
						BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));){
						
					//读取来自客户端的"问题"
					String question =reader.readLine();
					if(question==null||question.length()==0) {
						continue;
					}
					
					System.out.printf("来自客户端[%s]的问题:%s\n",clientIp,question);
					
					//查找并输出答案
					String answer=map.get(question);
					answer=answer==null?"对不起,我不知道你在说什么!":answer;
					
					//将问题的答案输出至"客户端"
					writer.write(answer);
				}
						
		
			}
		} catch (IOException e) {
			
			e.printStackTrace();
		}
	
	}
}
2.客户端程序
2.1步骤: 

首先创建一个Scanner对象input,用于从控制台读取用户输入的问题。用户输入的一行文本将存储在question字符串变量中。

接着尝试创建一个Socket对象clientSocket,连接到本地主机的 8848 端口,建立与服务器的连接。同时创建BufferedWriter对象writer和BufferedReader对象reader,分别用于向服务器发送数据和从服务器接收数据。

使用writer将question中的问题数据写入到Socket的输出流,并通过flush方法确保数据立即发送。

调用shutdownOutput方法关闭Socket的输出流,表示客户端数据发送完毕。

使用reader从Socket的输入流中读取服务器返回的一行回答数据,并存储在ans字符串变量中。

最后将服务器端的回答打印输出到控制台。

代码如下:

package com.ztt.tcp.Demo01;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
//人工智障对答程序【服务器】
public class AIzzServer {
	private static HashMap<String,String> map=new HashMap<String,String>();
	static {
		map.put("你好", "你好呀,孙子");
		map.put("hi", "hello,孙子");
		map.put("hello", "hi,孙子");
		map.put("吃了吗", "没呢,孙子");
		map.put("很高兴认识你", "我也是哦");
	}
	
	public static void main(String[] args) {
		try (ServerSocket serverSocket = new ServerSocket(8848)) {
			
			while(true) {
				Socket clientSocket=serverSocket.accept();
				String clientIp=clientSocket.getInetAddress().getHostAddress();
				
				//输入流:读取客户端发送的"问题"
				//输出流:发送问题的答案给客户端
				try(BufferedReader reader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
						BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));){
						
					//读取来自客户端的"问题"
					String question =reader.readLine();
					if(question==null||question.length()==0) {
						continue;
					}
					
					System.out.printf("来自客户端[%s]的问题:%s\n",clientIp,question);
					
					//查找并输出答案
					String answer=map.get(question);
					answer=answer==null?"对不起,我不知道你在说什么!":answer;
					
					//将问题的答案输出至"客户端"
					writer.write(answer);
				}
						
		
			}
		} catch (IOException e) {
			
			e.printStackTrace();
		}
	
	}
}

输出结果:

四、 图片在客户端与服务器端的传输

1.服务端的程序

代码如下:

package com.ztt.tcp.Demo01;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class imageServer {
	public static void main(String[] args) {
		//创建服务器端Socket对象,监听8848端口
		try(ServerSocket serverSocket=new ServerSocket(8848)){
			
			while(true) {
				Socket clientSocket=serverSocket.accept();
				
				InetAddress clientNetAddress=clientSocket.getInetAddress();
				System.out.printf("客户端%s正在连接图片服务器,即将上传图片......\n",clientNetAddress.getHostAddress());
				
				//上传图片名称
				String imageName=clientNetAddress.getHostAddress().replace('.', '-').concat(".jpg");
				
				try(InputStream in=clientSocket.getInputStream();
						BufferedInputStream bis=new BufferedInputStream(in);
						BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\test\\upload\\"+imageName));
						BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()))){
					
					//读取客户端上传的图片(字节输入流)
					byte[] buff=new byte[1024];
					int len=-1;
					while((len=bis.read(buff))!=-1) {
						bos.write(buff,0,len);
					}
					//给客户端反馈信息(字符输出流)
					writer.write("upload success!!!");
					writer.newLine();
					writer.write("--------->");
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}

2.客户端程序

代码如下:

package com.ztt.tcp.Demo01;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class imageClient {
	public static void main(String[] args) {
		try (Socket clientSocket = new Socket("192.168.199.103", 8848);
				BufferedInputStream in = new BufferedInputStream(
						new FileInputStream("D:\\test\\tt1\\tt.jpg"));
				BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
				BufferedOutputStream out = new BufferedOutputStream(clientSocket.getOutputStream());) {

			byte[] buff = new byte[1024];
			int len = -1;
			while ((len = in.read(buff)) != -1) {
				out.write(buff, 0, len);
			}
			out.flush();
			clientSocket.shutdownOutput();
			String line=null;
			while((line=reader.readLine())!=null) {
				System.out.println("服务器:"+line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 编写HttpServer服务器端代码,在浏览器根据Localhost:8080/查看

package com.ztt.tcp.Demo01;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;

public class HttpServer {
	public static void main(String[] args) {
		//创建服务器端Socket对象,监听8008端口
		try(ServerSocket serverSocket=new ServerSocket(8008)){
			while(true) {
				try (Socket clientSocket = serverSocket.accept();
						BufferedReader reader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {
						BufferedOutputStream out=new BufferedOutputStream(clientSocket.getOutputStream());
					//请求http请求报文
//					String line=null;
//					while((line=reader.readLine())!=null) {
//						System.out.println(line);
//					}
						//案例1
						//响应普通文本和html标签
//						out.write("HTTP/1.1 200 OK\r\n".getBytes());
//						out.write("Content-Type:text/html;charset=utf-8\r\n".getBytes());
//						out.write("Content-Length:343453\r\n".getBytes());
						
						//输出http相应报文
//						out.write("\r\n".getBytes());
//						out.write("天王盖地虎!!!\r\n".getBytes());
//						out.write("<br/>".getBytes());
//						out.write("<strong>".getBytes());
//						out.write((UUID.randomUUID().toString()+"\r\n").getBytes());
//						out.write("</strong>".getBytes());
//						out.flush();
//						
						//案例2
						byte[] imageBytes=Files.readAllBytes(Paths.get("D:\\test\\upload\\192-168-199-102.jpg"));
						out.write("HTTP/1.1 200 OK\r\n".getBytes());
						out.write("Content-Type:image/jpeg\r\n".getBytes());
						out.write(("Content-Length:"+imageBytes.length+"\r\n").getBytes());
						out.write("\r\n".getBytes());
						out.write(imageBytes);//响应输出图片
						out.flush();
						
				}
				
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

  • 16
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值