Java TCP编程之Scoket

 更新时间:2022年11月05日 17:22:30   作者:OlaiolaiO  
TCP/IP是一种面向连接的、可靠的、基于字节流的传输层通信协议,它会保证数据不丢包、不乱序。TCP全名是Transmission Control Protocol,它是位于网络OSI模型中的第四层

一、什么是Scoket

Socket 是一个抽象概念,一个应用程序通过一个 Socket 来建立一个远程连接,而 Socket 内部通 过 TCP/IP 协议把数据传输到网络。

┌───────────┐                                   ┌───────────┐
│Application│                                   │Application│
├───────────┤                                   ├───────────┤
│  Socket   │                                   │  Socket   │
├───────────┤                                   ├───────────┤
│    TCP    │                                   │    TCP    │
├───────────┤      ┌──────┐       ┌──────┐      ├───────────┤
│    IP     │<────>│Router│<─────>│Router│<────>│    IP     │
└───────────┘      └──────┘       └──────┘      └───────────┘

Socket 、 TCP 和部分 IP 的功能都是由操作系统提供的,不同的编程语言只是提供了对操作系统调 用的简单的封装。例如, Java 提供的几个 Socket 相关的类就封装了操作系统提供的接口: Server Socket 类、 Socket 类。

为什么需要 Socket 进行网络通信?因为仅仅通过 IP 地址进行通信是不够的,同 一台计算机同一时间会运行多个网络应用程序,例如浏览器、QQ、邮件客户端等。当 操作系统接收到一个数据包的时候,如果只有 IP 地址,它没法判断应该发给哪个应用 程序,所以,操作系统抽象出 Socket 接口,每个应用程序需要各自对应到不同的 S ocket ,数据包才能根据 Socket 正确地发到对应的应用程序。

一个 Socket 就是由IP地址和端口号(范围是0~65535)组成,可以把 Socket 简单理解为 IP 地址加端口号。端口号总是由操作系统分配,它是一个 0 ~ 65535 之间的数字,其中,小于 1024 的端口属于特权端口,需要管理员权限,大于 1024 的端口可以由任意用户的应用程序打开。

使用 Socket 进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进 程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它 必须主动连接服务器的 IP 地址和指定端口,如果连接成功,服务器端和客户端就成功 地建立了一个 TCP 连接,双方后续就可以随时发送和接收数据。

当 Socket 连接成功地在服务器端和客户端之间建立后:

  • 对服务器端来说,它的 Socket 是指定的 IP 地址和指定的端口号;
  • 对客户端来说,它的 Socket 是它所在计算机的 IP 地址和一个由操作系统分配的随机端口号。

二、服务器端

package com.ljl.tcp.demo2;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class ChatServer {
	public static void main(String[] args) {
		Map<String, String> chatMap = new HashMap<String, String>(){
			{
				put("你好", "你好呀");
				put("hi", "hi~");
				put("hello", "哈喽");
				put("吃了吗", "没呢,你呢");
				put("孤勇者", "爱你孤身走暗巷");
				put("有请潘周聃", "潘周聃,今年29岁,苏黎世理工大学.....");
				put("很高兴认识你", "我也是哦");
			}
		};
		try (ServerSocket server = new ServerSocket(9966)) {
			while(true) {
			//客户端连接
			Socket client = server.accept();
			//获取客户端IP地址
			String clientIP = client.getInetAddress().getHostAddress();
			try(
			BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
			BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));){	
			//获取客户端提问
			String question = reader.readLine();
			System.out.println("服务器来自客户端"+clientIP+"的提问:"+question);
			//获取问题答案
			String answer = chatMap.get(question);
			answer = answer == null?"我不知道你在说啥":answer;
			//发送答案至客户端
			writer.write(answer);
			}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

三、客户端

package com.ljl.tcp.demo2;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class ChatClient {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		while(true) {
		try (//创建Socket
		 Socket client = new Socket("192.168.254.163",9966);
			BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));	
			BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
			){
			//获取控制台的输入问题
			String question = input.nextLine();
			if(question.equals("退下")) {
				break;
			}
			//发送问题至服务器
			writer.write(question);
			writer.flush();
			//暂时结束本次输入
			client.shutdownOutput();
			//获取来自服务器的答案
			String answer = reader.readLine();
			System.out.println("服务器回答:"+answer);
		} catch (IOException e) {
			e.printStackTrace();
		}
		}
		System.out.println("over");
	}
}

四、Socket流

当 Socket 连接创建成功后,无论是服务器端,还是客户端,我们都使用 Socket 实例进行网络通信。因为 T CP 是一种基于流的协议,因此, Java 标准库使用 InputStream 和 OutputStream 来封装 Socket 的数据流,这 样我们使用 Socket 的流,和普通 IO 流类似:

// 用于读取网络数据:
InputStream in = sock.getInputStream();
// 用于写入网络数据:
OutputStream out = sock.getOutputStream();

写入网络数据时,必须要调用 flush() 方法。如果不调用 flush() ,我们很可能会发现,客户端和服务器都 收不到数据,这并不是 Java 标准库的设计问题,而是我们以流的形式写入数据的时候,并不是一写入就立刻发送 到网络,而是先写入内存缓冲区,直到缓冲区满了以后,才会一次性真正发送到网络,这样设计的目的是为了提高 传输效率。如果缓冲区的数据很少,而我们又想强制把这些数据发送到网络,就必须调用 flush() 强制把缓冲区数 据发送出去。

五、总结

使用Java进行TCP编程时,需要使用 Socket 模型:

  • 服务器端用 ServerSocket 监听指定端口;
  • 客户端使用 Socket(InetAddress, port) 连接服务器;
  • 服务器端用 accept() 接收连接并返回 Socket 实例;
  • 双方通过 Socket 打开 InputStream / OutputStream 读写数据;
  • 服务器端通常使用多线程同时处理多个客户端连接,利用线程池可大幅提升效率;
  • flush() 方法用于强制输出缓冲区到网络。

到此这篇关于Java TCP编程之Scoket的文章就介绍到这了,更多相关Java Scoket内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决springboot中自定义JavaBean返回的json对象属性名称大写变小写问题

    解决springboot中自定义JavaBean返回的json对象属性名称大写变小写问题

    开发过程中发现查询返回的数据出现自定义的JavaBean的属性值大小写格式出现问题,导致前端无法接受到数据,目前有四种解决方法,根据大佬的经验之谈,前两种是最简单便捷的,后两种是比较通用的方法,需要的朋友可以参考下
    2023-10-10
  • Spring Boot Actuator 漏洞利用小结

    Spring Boot Actuator 漏洞利用小结

    spring对应两个版本,分别是Spring Boot 2.x和Spring Boot 1.x,因此后面漏洞利用的payload也会有所不同,这篇文章主要介绍了Spring Boot Actuator 漏洞利用小结,需要的朋友可以参考下
    2023-11-11
  • JDK、J2EE、J2SE、J2ME四个易混淆概念区分

    JDK、J2EE、J2SE、J2ME四个易混淆概念区分

    这篇文章将向你详细介绍JDK、J2EE、J2SE、J2ME的概念以及他们的关系区别。
    2015-09-09
  • 详解在Spring MVC或Spring Boot中使用Filter打印请求参数问题

    详解在Spring MVC或Spring Boot中使用Filter打印请求参数问题

    这篇文章主要介绍了详解在Spring MVC或Spring Boot中使用Filter打印请求参数问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Java报错:Error:java: 程序包org.springframework.boot不存在解决办法

    Java报错:Error:java: 程序包org.springframework.boot不存在解决办法

    建完springboot项目时,点击启动,有可能会报错,下面这篇文章主要给大家介绍了关于Java报错:Error:java: 程序包org.springframework.boot不存在的解决办法,需要的朋友可以参考下
    2024-02-02
  • 一文掌握SpringSecurity BCrypt密码加密和解密

    一文掌握SpringSecurity BCrypt密码加密和解密

    BCrypt就是一款加密工具,可以比较方便地实现数据的加密工作。也可以简单理解为它内部自己实现了随机加盐处理,这篇文章主要介绍了SpringSecurity BCrypt密码加密和解密,一文学会使用BCryptPasswordEncoder的方法,需要的朋友可以参考下
    2023-04-04
  • Spring中的@ControllerAdvice和ResponseBodyAdvice详解

    Spring中的@ControllerAdvice和ResponseBodyAdvice详解

    这篇文章主要介绍了Spring中的@ControllerAdvice和ResponseBodyAdvice详解,@ControllerAdvice作用于@Controller修饰的类里面的所有方法,ResponseBodyAdvice作用于@ResponseBody注解修饰的方法,它可以对这些方法的返回值进行修改,需要的朋友可以参考下
    2024-01-01
  • 详解SpringBoot中@NotNull,@NotBlank注解使用

    详解SpringBoot中@NotNull,@NotBlank注解使用

    这篇文章主要为大家详细介绍了Spring Boot中集成Validation与@NotNull,@NotBlank等注解的简单使用,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-08-08
  • java如何自定义List中的sort()排序,用于日期排序

    java如何自定义List中的sort()排序,用于日期排序

    这篇文章主要介绍了java如何自定义List中的sort()排序,用于日期排序,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • 浅谈Java8新特性Predicate接口

    浅谈Java8新特性Predicate接口

    这篇文章主要介绍了浅谈Java8新特性Predicate接口,文中有非常详细的代码示例,对正在学习java的小伙伴们有很好的帮助,需要的朋友可以参考下
    2021-05-05

最新评论