目录

1.socket简介

2.TCP/IP协议

3.tcp三次握手

4.socket的一些接口函数原理

5.java socket 长连接粘包拆包问题

6.socket模拟服务端客户端发消息

7.UDP广播发请求


C socket编程代码及简介

java socket代码样例 详细

WebSocket与Socket、TCP、HTTP的关系和异同点

最近因为客户需求开始接触网络编程,过程很心酸,收获很丰满。。。

1.socket简介

socket编程是一门技术,他主要在网络通信中经常用到。

既然是一门技术,由于现在是面向对象的编程,一些计算机行业的大神通过抽象的理念,在现实中通过反复或者实际的推导,提出了抽象的一些通信协议,基于tcp/ip协议,提出大致的构想,一些泛型的程序大牛在这个协议的基础上,将这些抽象化的理念接口化,针对协议提出的每个理念,专门的编写指定的接口,与其协议一一对应,形成了现在的socket标准规范,然后将其接口封装成可以调用的接口,供开发者使用。

目前开发者开发出了很多封装的类来完善socket编程,都是更加方便的实现刚开始socket通信的各个环节,所以我们必须首先了解socket的通信原理,只有从本质上理解socket的通信,才可能快速方便的理解socket的各个环节,才能从底层上真正的把握。

2.TCP/IP协议

要理解socket必须的得理解tcp/ip,它们之间好比送信的线路和驿站的作用,比如要建议送信驿站,必须得了解送信的各个细节。

TCP/IP协议不同于iso的7个分层,它是根据这7个分层,将其重新划分,好比打扫卫生,本来有扫帚,垃圾斗,抹布,涂料,盆栽等就好比OSI的标准几个分层,tcp/ip根据用途和功能,将扫帚,垃圾斗放到粗略整理层,抹布涂料放到中度整理层,盆栽放到最终效果层。这里TCP/IP也对OSI的网络模型层进行了划分:大致如下:

OSI模型:

TCP/IP协议参考模型把所有的TCP/IP系列协议归类到四个抽象层中:

应用层:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等

传输层:TCP,UDP

网络层:IP,ICMP,OSPF,EIGRP,IGMP

数据链路层:SLIP,CSLIP,PPP,MTU

每一抽象层建立在低一层提供的服务上,并且为高一层提供服务,看起来大概是这样子的:

通过上面的图形,由于底一层的需要向高一层的提供服务,我们大致的理解应用程序需要传输层的tcp和网络层的ip协议提供服务,但是我们这章要分析的socket它是在tcpip协议的那一部分呢,就好比,我们的通讯线路已经有明确的规定,我们的驿站要设计在哪个地方一样。

回过头再来理解socket

到目前为止,大致的了解了应用程序和tcpip协议的大致关系,我们只是知道socket编程是在tcp/IP上的网络编程,但是socket在上述的模型的什么位置呢?这个位置被一个天才的理论家或者是抽象的计算机大神提出并且安排出来:

我们可以发现socket就在应用程序的传输层和应用层之间,设计了一个socket抽象层,传输层的底一层的服务提供给socket抽象层,socket抽象层再提供给应用层,问题又来了,应用层和socket抽象层之间和传输层,网络层之间如何通讯的呢,了解这个之前,我们还是回到原点。

要想理解socket编程怎么通过socket关键词实现服务器和客户端通讯,必须得实现的了解tcp/ip是怎么通讯的,在这个的基础上在去理解socket的握手通讯。

3.tcp三次握手

在tcp/ip协议中,tcp通过三次握手建立起一个tcp的链接,大致如下:

第一次握手:客户端尝试连接服务器,向服务器发送syn包,syn=j,客户端进入SYN_SEND状态等待服务器确认

第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

三次握手如下图:

根据tcp的三次握手,socket也定义了三次握手,也许是参考tcp的三次握手,一些计算机大神们画出了socket的三次握手的模型图

模型图如下:

在上面图的基础上,如果我们得到上面的图形,需要我们自己开发一些接口,来满足上面的通讯的三次握手,问题就出来了,我们会需要开发哪些函数?

4.socket的一些接口函数原理

通过上面的图,我们清楚,我们好比一些泛型的程序员,一些理论提供者提供给了我们上面的图形的理论,我们需要做的就是讲上面的图形的抽象化的东西具体化。

第一次握手:客户端需要发送一个syn j 包,试着去链接服务器端,于是客户端我们需要提供一个链接函数

第二次握手:服务器端需要接收客户端发送过来的syn J+1 包,然后在发送ack包,所以我们需要有服务器端接受处理函数

第三次握手:客户端的处理函数和服务器端的处理函数

三次握手只是一个数据传输的过程,但是,我们传输前需要一些准备工作,比如将创建一个套接字,收集一些计算机的资源,将一些资源绑定套接字里面,以及接受和发送数据的函数等等,这些功能接口在一起构成了socket的编程

下面大致的按照客户端和服务端将所需的函数详细的列举出来:

上面的两个图都概述了socket的通讯原理

socket 样例可点击java socket代码样例 详细

5.java socket 长连接粘包拆包问题

网上看了很多资料,没有很好可实行的成熟的方案,最后在我师傅的英明带领下,socket粘包拆包问题算是解决了,demo所做的工作就是将通过socket长连接发过来的包,拆成一条一条完整的包供安卓使用。直接上代码:

package socket;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;/*** java客户端*/
public class SocketClient extends Thread {private static final Logger logger = LoggerFactory.getLogger(SocketClient.class);private static boolean flag = false;public static Socket socket = new Socket();public static void main(String[] args) throws IOException {try {connect();String bookAlarm = "POST /merlin/BookAlarmCenter.cgi HTTP/1.1\r\n" +"Content-Length: 0\r\n" +"Content-Type: application/json\r\n" +"User-Agent: 172.18.30.120:80\r\n" +"Connection: keep-alive\r\n" +"Authorization: Basic YWRtaW46MTIzNDU2\r\n";// 向服务端发消息sendMessage(bookAlarm);// 持续接受服务端消息receiveMessage();} catch (Exception e) {logger.info("异常关闭,异常信息:{}", e);}socket.close();logger.info("客户端已退出~");}/*** 接受服务端消息* @throws IOException*/private static void receiveMessage() throws IOException {// 得到socket输入流,并转换为BufferedReaderInputStream inputStream = socket.getInputStream();String tag = "\r\n\r\n";String tag2 = "\r\n";ByteArrayOutputStream output = new ByteArrayOutputStream();int n;while ((n = inputStream.read()) != -1) {if (flag) {output = new ByteArrayOutputStream();flag = false;}output.write(n);String headStr = output.toString();int contentLength = 0;if (headStr.contains(tag)) {String[] split = headStr.split(tag2);for (String contentLine : split) {if (contentLine.contains("Content-Length:")) {contentLength = Integer.parseInt(contentLine.split("Content-Length:")[1].trim());break;}}int count = 0;while ((n = inputStream.read()) != -1) {output.write(n);count++;if (count == contentLength) {System.out.println(output.toString());System.out.println("========================================================================================================");flag = true;break;}}}}}private static void connect() {try {// 超时时间socket.setSoTimeout(30 * 1000);// 连接本地,超时时间3ssocket.connect(new InetSocketAddress("172.18.30.107", 80), 30 * 1000);logger.info("已发起服务器连接,并进入后续流程");logger.info("客户端信息:" + socket.getLocalAddress() + " port:" + socket.getLocalPort());logger.info("服务端信息:" + socket.getInetAddress() + " port:" + socket.getPort());} catch (Exception e) {logger.error("连接服务器异常,异常信息:{}", e);}}/*** 向服务端发消息* @param message* @throws IOException*/public static void sendMessage(String message) {// 得到socket输出流,并转换为打印流OutputStream outputStream;PrintStream socketPrintStream;try {outputStream = socket.getOutputStream();// 用此方法发送可收到回包socketPrintStream = new PrintStream(outputStream);logger.info("向服务端发消息:{}", message);socketPrintStream.println(message);} catch (Exception e) {logger.error("客户端发送消息异常:{}", e);}}}

6.socket模拟服务端客户端发消息

客户端:

import java.io.*;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;/*** 客户端*/
public class Client {public static void main(String[] args) throws IOException{
//        Socket socket = new Socket();Socket socket = new Socket("192.168.9.113", 80);// 超时时间socket.setSoTimeout(3000);// 连接本地,端口2000;超时时间3ssocket.connect(new InetSocketAddress(Inet4Address.getLocalHost(), 2000), 3000);System.out.println("已发起服务器连接,并进入后续流程");System.out.println("客户端信息:" + socket.getLocalAddress() + ",port:" + socket.getLocalPort());System.out.println("服务端信息:" + socket.getInetAddress() + ",port:" + socket.getPort());try {todo(socket);} catch(Exception e) {System.out.println("异常关闭");}socket.close();System.out.println("客户端已退出~");}private static void todo(Socket socket) throws IOException {// 构建键盘输入流InputStream in = System.in;BufferedReader input = new BufferedReader(new InputStreamReader(in));// 得到socket输出流,并转换为打印流OutputStream outputStream = socket.getOutputStream();PrintStream socketPrintStream = new PrintStream(outputStream);// 得到socket输入流,并转换为BufferedReaderInputStream inputStream = socket.getInputStream();BufferedReader socketBufferedReader = new BufferedReader(new InputStreamReader(inputStream));boolean flag = true;do {// 键盘读取一行String str = input.readLine();// 发送到服务器socketPrintStream.println(str);// 从服务器读取一行String echo = socketBufferedReader.readLine();if ("bye".equalsIgnoreCase(echo)) {flag = false;} else {System.out.println(echo);}} while (flag);// 资源释放socketBufferedReader.close();socketPrintStream.close();}
}

服务端:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;/*** 基于TCP协议的Socket通信,实现用户登录,服务端*/
public class Server {public static void main(String[] args) throws IOException{ServerSocket server = new ServerSocket(80);System.out.println("服务器准备就绪~");System.out.println("服务端信息:" + server.getInetAddress() + "port:" + server.getLocalPort());// 等待客户端连接for (;;) {// 得到客户端Socket client = server.accept();// 客户端构建异步线程ClientHandler clientHandler = new ClientHandler(client);// 启动线程clientHandler.start();}}/*** 客户端消息处理*/private static class ClientHandler extends Thread {private Socket socket;private boolean flag = true;ClientHandler (Socket socket) {this.socket = socket;}@Overridepublic void run() {super.run();System.out.println("新客户端连接:" + socket.getInetAddress() + ",port:" + socket.getPort());try {// 得到打印流,用于数据输出,服务器回送数据使用PrintStream socketOutPut = new PrintStream(socket.getOutputStream());BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));do {// 客户端拿到一条数据String str = socketInput.readLine();if ("bye".equalsIgnoreCase(str)) {flag = false;// 回送socketOutPut.println("bye");} else {// 打印到屏幕,并回数据长度System.out.println("客户端发来消息:" + str);socketOutPut.println("回送:" + str.length());// 回送客户端}} while (flag);socketInput.close();socketOutPut.close();} catch(Exception e) {System.out.println("连接异常断开");} finally {// 连接关闭try {socket.close();} catch (IOException e) {e.printStackTrace();}}System.out.println("客户端已退出:" + socket.getInetAddress() + "port:" + socket.getPort());}}}

7.UDP广播发请求

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;/*** @Description:     DUP提供者,用于提供服务* @Author:          nicecloud* @CreateDate:      2019/6/29 22:55* @Version:         1.0*/
public class UDPProvider {public static void main(String[] args) throws IOException {System.out.println("UDPProvider started.");// 作为接收者,指定一个端口用于数据接收DatagramSocket ds = new DatagramSocket(20000);// 构建接收实体final byte[] buf = new byte[512];DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);// 接收ds.receive(receivePacket);// 打印接收到的信息与发送者的信息// 发送者的IP地址String ip = receivePacket.getAddress().getHostAddress();int port = receivePacket.getPort();int dataLen = receivePacket.getLength();String data = new String(receivePacket.getData(), 0, dataLen);System.out.println("UDPProvider receive from ip:" + ip + "\tport:" + port + "\tdata:" + data);// 构建一份回送数据String responseData = "Receive data with len:" + dataLen;byte[] responDataBytes = responseData.getBytes();// 直接根据发送者构建一份回送信息DatagramPacket responsePacket = new DatagramPacket(responDataBytes,responDataBytes.length,receivePacket.getAddress(),receivePacket.getPort());ds.send(responsePacket);// 完成System.out.println("UDPProvider Finished.");ds.close();}
}
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;/*** @Description:* @Author:          nicecloud* @CreateDate:      2019/6/29 22:56* @Version:         1.0*/
public class UDPSearcher {public static void main(String[] args) throws IOException {System.out.println("UDPSearcher started.");// 作为搜索方,无需指定端口,系统自动分配DatagramSocket ds = new DatagramSocket(20000);// 构建一份回送数据String receiveData = "hello udp!";byte[] requestDataBytes = receiveData.getBytes();// 直接根据发送者构建一份回送信息DatagramPacket requestPacket = new DatagramPacket(requestDataBytes,requestDataBytes.length);// 本机端口20000requestPacket.setAddress(InetAddress.getLocalHost());requestPacket.setPort(20000);// 发送ds.send(requestPacket);// 构建接收实体final byte[] buf = new byte[512];DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);// 接收ds.receive(receivePacket);// 打印接收到的信息与发送者的信息// 发送者的IP地址String ip = receivePacket.getAddress().getHostAddress();int port = receivePacket.getPort();int dataLen = receivePacket.getLength();String data = new String(receivePacket.getData(), 0, dataLen);System.out.println("UDPSearcher receive from ip:" + ip + "\tport:" + port + "\tdata:" + data);// 完成System.out.println("UDPSearcher Finished.");ds.close();}
}

(Java)socket网络编程及处理socket粘包拆包问题相关推荐

  1. java tcp怎么拆包_Java网络编程基础之TCP粘包拆包

    TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想象河里的流水,他们是连成一片的,其间并没有分界线.TCP底层并不了解上层业务数据的具体含义,他会根据TCP缓冲区的实 ...

  2. socket网络编程python_python之SOCKET网络编程

    一.socket解释 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面 ...

  3. socket网络编程及通过socket接口实现一个自我通信的简易UDP服务器

    网络编程socket基础 认识socket套接字 先用一张图引出socket的内容 根据上面的图示我们可以知道socket其实是位于应用层与传输层之间的一层软件抽象层.它是一组接口,在后面的部分我们会 ...

  4. 【Socket网络编程】0.socket TCP/UDP 可参考 【lx青萍之末】 的 【Linux网络编程 】系列博客

    关于socket TCP/UDP 相关知识 可参考博主[ lx青萍之末] 的 [Linux网络编程 ]系列博客 https://blog.csdn.net/daaikuaichuan/category ...

  5. 【NIO与Netty】网络编程:netty中粘包、半包现象展示,分析及解决

    一.粘包现象 服务端 public static void main(String[] args) {NioEventLoopGroup bossGroup=new NioEventLoopGroup ...

  6. socket网络编程(2):socket操作相关函数

    使用socket函数应先包含winsock2.h头文件和链接Ws2_32.lib文件: #include <winsock2.h> #pragma comment(lib, "W ...

  7. 【Socket网络编程】7.以太网数据包、IP数据包、UDP数据包

    以太网数据包.ip数据包.udp数据包 搭配这篇博文服用,效果更好:数据封装 和 数据拆封:https://blog.csdn.net/u011754972/article/details/11794 ...

  8. linux java socket编程_深入学习socket网络编程,以java语言为例

    了解java的socket编程与Linux Socket API之间的关系 一.java的网络编程 1.socket原理 socket通信就是通过IP和端口号将两台主机建立连接,提供通信.主机A的应用 ...

  9. Java之socket网络编程

    socket网络编程 文章目录 socket网络编程 一.网络编程概述 二.网络通信要素概述 三.IP和端口号 四.网络协议 五.TCP网络编程 六.UDP网络编程 一.网络编程概述 网络编程的目的 ...

最新文章

  1. python人脸识别项目_基于Python与命令行人脸识别项目(系列二)
  2. 练习:自己写一个容器ArrayList集合 一一数组综合练习2
  3. 老大难的 Java ClassLoader,到了该彻底理解它的时候了
  4. 网络实验: 总线型以太网的特性---广播、竞争总线(冲突)
  5. sp_executesql介绍和使用
  6. 面向对象的数据存储方式
  7. 论文小综 | Using External Knowledge on VQA
  8. 【C语言】成绩统计(结构)
  9. 第十三:Pytest参数化-@pytest.mark.parametrize装饰器来实现数据驱动测试
  10. redis 数据类型详解 以及 redis适用场景场合
  11. 第02章:字符串是否包含
  12. 手机网站支付-支付宝API-Python
  13. pc端MNIST数据集pytorch模型CNN网络转换为onnx部署树莓派4B和神经棒NCS2(使用openvino2021框架)
  14. 办理营业执照注册要什么费用
  15. android微信图片选择框架,Android仿微信图片选择器ImageSelector使用详解
  16. 《网络攻防》第七周学习总结
  17. 按位与和异或运算符(Python中两个不常用,却重要的运算符)
  18. 边缘计算:新瓶装旧酒?
  19. 八种酒吧里最IN喝酒法PartyOK版
  20. 科大讯飞语音听写app闪退

热门文章

  1. C语言——一分钟了解数据类型与变量
  2. 数据挖掘在金融行业十大应用
  3. proguard配置选项
  4. NCCL源码解析②:Bootstrap网络连接的建立
  5. C# 海量数据导出到 Excel
  6. 201671010434王雯涵--实验二 软件工程个人项目
  7. 如何设置虚拟机为静态IP
  8. 出现腰肌劳损怎么办?治疗护理6步走,帮你摆脱痛苦
  9. vscode 最详细的调试
  10. pytorch学习笔记(一)-- 《深度学习入门》红色石头