TCP协议服务端与客户端

2023-11-05

一、TCP/IP协议简介

什么是TCP/IP

TCP/IP协议是一种用于因特网的通信协议。TCP指传输控制协议(Transmission Control Protocol),IP指网际协议(Internet Protocol)。

TCP/IP协议簇中的协议

TCP/IP协议是一个协议簇,其中包含许多协议,囊括了应用层、传输层、网络层以及网络访问层。

  • 应用层包括:
    ①超文本传输协议(HTTP),万维网的基本协议
    ②TFTP文件传输协议
    ③Telnet远程登录协议
    ④SNMP网络管理协议
    ⑤DNS域名解析
  • 网络层包括:
    ①网际(IP)协议
    ②因特网消息控制协议ICMP
    ③ARP地址解析协议
    ④RARP反向地址解析协议
  • 网络访问层:
    网络访问层是TCP/IP协议簇的最底层,它提供物理网络的接口,实现对复杂数据的发送和接收。网络访问层协议为网络接口、数据传输提供了对应的技术规范。TCP/IP中的网络访问层对应OSI七层网络模型中的物理层和数据链路层。
    OSI七层网络模型

TCP、UDP的区别

TCP、UDP都是TCP/IP协议簇中的通信协议,其中TCP(Transmission Control Protocol)是面向连接的协议,而UDP(User Data Protocol)则是一个非连接的协议。

二、TCP协议应用

TCP的三次握手

TCP协议在进行数据通信之前必须建立连接,而TCP建立连接采用“三次握手”的方式。
TCP的三次握手
三次握手的过程就像打电话,如下:
小刘打电话给王哥,这个打电话的动作即发起连接请求(第一次握手),王哥听到来电铃声接起电话并说:“喂,小刘啊,听得到吗?”,这一步骤就如上图服务端响应客户端的连接请求(第二次握手),这时小刘听见电话里传来王哥的声音,知道王哥已经响应,便说道:“王哥,可以听到。”,这一步即上图中客户端对服务端的第三次握手,此时连接便已成功建立,小刘(客户端)和王哥(服务端)就可以进行通信了。

TCP的四次挥手

四次挥手
如同三次挥手像打电话一样,四次挥手也可以像挂断电话一般。如下:
小刘(客户端):王哥,事情大概就是这个样子。
王哥(服务端):好,这个事情你放心,没问题。
王哥(服务端):小刘,没啥事的话我就挂了啊。
小刘(客户端):好嘞,再见王哥。
此时连接断开。
拨打/挂断电话跟TCP的三次握手/四次挥手过程不完全一致,但可以用这个过程去初步理解,初步理解后再根据其原理进行深入理解。

TCP服务器

TCP服务器建立的流程是创建套接字、绑定套接字、监听套接字,然后进行收发消息、处理消息的操作。

1、创建套接字

函数原型,TCP协议的通信依靠套接字,在使用套接字之前,需要先使用socket()函数创建套接字,使用该函数时需要传入地址族(af)、数据传输方式/套接字类型(type)、传输协议三个参数(protocol)。
af为地址族(Address Family),即IP地址类型,常用的有AF_INET和AF_INET6。AF是"Address Family"的简写,INET是"Internet"的简写。AF_INET表示的是IPV4地址,AF_INET6则表示的是IPV6地址。(也可以使用PF(Protocol Family)前缀,与AF一致)
type为数据传输方式/套接字类型,常用的有SOCK_STREAM(数据流式套接字/面向连接的套接字)和SOCK_DGRAM(数据报式套接字/无连接的套接字)。
protocol为传输协议,常用的有IPPROTO_TCP和IPPROTO_UDP,分别表示TCP传输协议和UDP传输协议。在使用TCP或UDP协议时,由于SOCK_STREAM和SOCK_DGRAM分别只能用于TCP、UDP,因此该参数可以填0,系统会自行适配传输协议。

int socket(int af, int type, int protocol);
INT sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(0 > sockfd)
{
    SaveLog(MODULE_TCPSERVER, "ERROR:Create socket fail\r\n");
    return -1;
}

2、绑定、监听套接字

函数原型,sock为socket文件描述符,addr为sockaddr结构体变量的指针,addrlen为addr变量的大小。

int bind(int sock, struct sockaddr *addr, socklen_t addrlen);
struct sockaddr_in ServerAddr = {0};
memset(&ServerAddr, 0, sizeof(ServerAddr));
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(SERVER_PORT);
ServerAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
if(0 > bind(sockfd, (struct sockaddr*)&ServerAddr,sizeof(ServerAddr)))
{
    SaveLog(MODULE_TCPSERVER, "ERROR:Bind failed\r\n");
    return -1;
}

函数原型,sock为socket文件描述符,backlog为请求队列的最大长度。

int listen(int sock, int backlog);
if(0 < listen(sockfd, SERVER_MAX_CON))
{
    SaveLog(MODULE_TCPSERVER, "ERROR:Listen failed\r\n");
    return -1;
}
return sockfd;

3、接收连接

TCP服务器完成套接字的创建、绑定与监听操作后,需要调用accept函数接收客户端的连接,函数原型为:

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);

accpet()函数的参数与listen()函数的一致,不过返回值为客户端的socket描述符。

INT connfd = 0;
connfd = accept(sockfd, NULL, NULL);
if(0 > connfd)
{
    SaveLog(MODULE_TCPSERVER, "ERROR:accept failed\r\n");
}

4、数据传输

连接建立后,即可进行数据的传输。主要使用recv()函数和send()函数。函数原型如下:

int send(SOCKET sock, const char *buf, int len, int flags);
int recv(SOCKET sock, char *buf, int len,int flags);

其中,sock为套接字,buf为要发送或者存储接收数据的缓冲区地址,len为发送/接收的数据的字节数,flags为发送/接收数据的选项(一般为0或者NULL即可)。recv()函数和send()函数的返回值都为接收/发送的实际字节数。

struct sockaddr ClientAddr = {0};
struct sockaddr_in ClientAddrIn = {0};
INT iRes = 0;
ULONG ulNameLen = 0;
CHAR *szBuf[1024] = {0};

memset(&ClientAddr, 0, sizeof(ClientAddr));
memset(&ClientAddrIn, 0, sizeof(ClientAddrIn));
ulNameLen = sizeof(struct sockaddr);
connfd = (INT *)void_sockfd;

if(0 == getsockname(connfd, &ClientAddr, (socklen_t *)&ulNameLen))
{
    memcpy(&ClientAddrIn, &ClientAddr, ulNameLen);
    SaveLog(MODULE_TCPSERVER, "INFO:Client connect,IP:%s:%d\r\n",inet_ntoa(ClientAddrIn.sin_addr),ntohs(ClientAddrIn.sin_port));
}
else
{
    SaveLog(MODULE_TCPSERVER, "ERROR:Get client IP address failed\r\n");
}
while(1)
{
    iRes = recv(connfd, szBuf, sizeof(szBuf), 0);
    if(0 > iRes)
    {
        SaveLog(MODULE_TCPSERVER, "ERROR:Recv buf From %s failed,iRes:%d\r\n", inet_ntoa(ClientAddrIn.sin_addr), iRes);            
    }
    else if(iRes > 0)
    {
        SaveLog(MODULE_TCPSERVER, "INFO:Recv buf:%s From:%s\r\nLen:%d\r\n", szBuf, inet_ntoa(ClientAddrIn.sin_addr), iRes);
    }
    else
    {
        SaveLog(MODULE_TCPSERVER, "INFO:Connect From %s stop\r\n", inet_ntoa(ClientAddrIn.sin_addr));
        return;
    }
}

服务器实例:

#include "tcp_server.h"
#include "../log/log.h"

VOID main()
{
    INT sockfd = 0;

    sockfd = Socket_Init();
    if(0 > sockfd)
    {
        printf("exec failed\r\n");
        return;
    }
    Socket_Process(sockfd);
}

INT Socket_Init()
{
    INT sockfd = 0;    
    struct sockaddr_in ServerAddr = {0};
    
    memset(&ServerAddr, 0, sizeof(ServerAddr));

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(0 > sockfd)
    {
        SaveLog(MODULE_TCPSERVER, "ERROR:Create socket fail\r\n");
        return -1;
    }

    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(SERVER_PORT);
    ServerAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    if(0 > bind(sockfd, (struct sockaddr*)&ServerAddr,sizeof(ServerAddr)))
    {
        SaveLog(MODULE_TCPSERVER, "ERROR:Bind failed\r\n");
        return -1;
    }
    if(0 < listen(sockfd, SERVER_MAX_CON))
    {
        SaveLog(MODULE_TCPSERVER, "ERROR:Listen failed\r\n");
        return -1;
    }
    return sockfd;
}

VOID Socket_Process(INT sockfd)
{
    INT connfd = 0; 
    pthread_t th_process;

    while(1)
    {
        connfd = accept(sockfd, NULL, NULL);
        if(0 > connfd)
        {
            SaveLog(MODULE_TCPSERVER, "ERROR:accept failed\r\n");
        }
        /* 连接成功后进入线程 */
        pthread_create(&th_process, NULL, Server_Process, (VOID *)connfd);        
    }
}

VOID Server_Process(VOID *void_sockfd)
{
    INT connfd = 0;
    struct sockaddr ClientAddr = {0};
    struct sockaddr_in ClientAddrIn = {0};
    INT iRes = 0;
    ULONG ulNameLen = 0;
    CHAR *szBuf[1024] = {0};

    memset(&ClientAddr, 0, sizeof(ClientAddr));
    memset(&ClientAddrIn, 0, sizeof(ClientAddrIn));
    ulNameLen = sizeof(struct sockaddr);
    connfd = (INT *)void_sockfd;

    if(0 == getsockname(connfd, &ClientAddr, (socklen_t *)&ulNameLen))
    {
        memcpy(&ClientAddrIn, &ClientAddr, ulNameLen);
        SaveLog(MODULE_TCPSERVER, "INFO:Client connect,IP:%s:%d\r\n",inet_ntoa(ClientAddrIn.sin_addr),ntohs(ClientAddrIn.sin_port));
    }
    else
    {
        SaveLog(MODULE_TCPSERVER, "ERROR:Get client IP address failed\r\n");
    }
    while(1)
    {
        iRes = recv(connfd, szBuf, sizeof(szBuf), 0);
        if(0 > iRes)
        {
            SaveLog(MODULE_TCPSERVER, "ERROR:Recv buf From %s failed,iRes:%d\r\n", inet_ntoa(ClientAddrIn.sin_addr), iRes);            
        }
        else if(iRes > 0)
        {
            SaveLog(MODULE_TCPSERVER, "INFO:Recv buf:%s From:%s\r\nLen:%d\r\n", szBuf, inet_ntoa(ClientAddrIn.sin_addr), iRes);
        }
        else
        {
            SaveLog(MODULE_TCPSERVER, "INFO:Connect From %s stop\r\n", inet_ntoa(ClientAddrIn.sin_addr));
            return;
        }
    }
}

TCP客户端

如同服务器,TCP客户端在数据传输之前也需要创建套接字,不同于服务器的是,客户端创建套接字后无需绑定、监听操作,直接使用connect()函数连接至服务器即可。

/************************  
函数名:connect
参数:sock  套接字
	server_addr  服务器地址结构体
	addrlen  服务器地址结构体大小
返回值:0为成功,小于0失败
************************/
int connect(int sock, struct sockaddr *server_addr, socklen_t addrlen);

客户端实例

VOID main()
{
    INT sockfd = 0;   

    sockfd = ConnectServer();
    Client_Process(sockfd);   
}

VOID Client_Process(INT sockfd)
{
    INT i = 0;
    INT iRes   = 0;
    INT iMsgLen = 0;
    CHAR szBuf[1024] = {0};
    CHAR szHead[TCP_MSG_HEAD_LEN] = {0};
    sprintf(szBuf, "This is a hello msg!\r\nIs used to do test for server");
    /* 组装消息头 */
    iMsgLen = strlen(szBuf);
    PackMsgHead(MSG_PRINT, iMsgLen, szHead);
    /* 发送消息头 */
    iRes = send(sockfd, szHead, TCP_MSG_HEAD_LEN, 0);
    if(0 > iRes)
    {
        SaveLog(MODULE_TCPCLIENT, "ERROR:Send buf failed,iRes:%d\r\n", iRes);
        return;
    }
    SaveLog(MODULE_TCPCLIENT, "INFO:Send head:%s\r\nLen:%d\r\n", szHead, iRes);
    sleep(1);
    /* 发送消息体 */
    iRes = send(sockfd, szBuf, iMsgLen, 0);
    if(0 > iRes)
    {
        SaveLog(MODULE_TCPCLIENT, "ERROR:Send buf failed,iRes:%d\r\n", iRes);
        return;
    }
    SaveLog(MODULE_TCPCLIENT, "INFO:Send buf:%s\r\nLen:%d\r\n", szBuf, iRes);
    sleep(1);
    while(1);
}

INT ConnectServer()
{
    INT sockfd = 0;
    struct sockaddr_in cli_addr;

    memset(&cli_addr, 0, sizeof(cli_addr));
    cli_addr.sin_family = AF_INET;
    cli_addr.sin_port   = htons(SERVER_PORT);
    cli_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        SaveLog(MODULE_TCPCLIENT, "ERROR:Create socket fail\r\n");
        return -1;
    }
    if(0 > connect(sockfd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
    {
        SaveLog(MODULE_TCPCLIENT, "ERROR:connect server failed\r\n");
        return -1;
    }
    SaveLog(MODULE_TCPCLIENT, "INFO:connect server success\r\n");
    return sockfd;
}

VOID PackMsgHead(TCP_MSG_TYPE_E eMsgType, ULONG ulMsgLen, CHAR *pcOutBuf)
{
    if(NULL == pcOutBuf)
    {
        SaveLog(MODULE_TCPCLIENT, "Buf is null");
        return;
    }
    TCP_MSG_HEAD_S stTcpMsgHead;
    memset(&stTcpMsgHead, 0, sizeof(stTcpMsgHead));
    stTcpMsgHead.eMsgType = eMsgType;
    stTcpMsgHead.ulMsgLen = ulMsgLen;
    memcpy(pcOutBuf, (CHAR *)&stTcpMsgHead, sizeof(stTcpMsgHead));
}

相关结构体、宏定义等

/* tcp_client.h */
#ifndef _TCP_CLIENT_H_
#define _TCP_CLIENT_H_

#include "../../common/common.h"

#define SERVER_PORT     14000           //TCP服务器使用的端口号
#define SERVER_IP       "192.168.1.80"  //服务器IP地址

INT ConnectServer();
VOID Client_Process(INT sockfd);

#endif


/* tcp_server.h */
#ifndef _TCP_SERVER_H_
#define _TCP_SERVER_H_

#include "../../common/common.h"

#define SERVER_PORT     14000
#define SERVER_MAX_CON  100		//最大连接数
#define SERVER_IP       "192.168.0.80"
#define MAX_LOG_SIZE    4096

INT  Socket_Init();
VOID Socket_Process(INT sockfd);
VOID Server_Process(VOID *void_sockfd);

#endif


/* tcp.h */
#ifndef _TCP_H_
#define _TCP_H_
#include "../common/common.h"

#define TCP_MSG_HEAD_LEN sizeof(TCP_MSG_HEAD_S)

typedef enum
{
    MSG_PRINT = 0xFF00, //0xFF00
    MSG_ERROR           //0xFF01
}TCP_MSG_TYPE_E;

typedef struct tagTcpMsgHead
{
    TCP_MSG_TYPE_E eMsgType;
    ULONG ulMsgLen;
}TCP_MSG_HEAD_S;

#endif


/* common.h */
#ifndef _COMMON_H_
#define _COMMON_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stddef.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <pthread.h>
#include <time.h>
#include <uinstd.h>

#define INT         int
#define CHAR        char
#define FLOAT       float
#define DOUBLE      double
#define SHORT       short
#define LONG        long
#define UINT        unsigned int
#define ULONG       unsigned long
#define UCHAR       unsigned char
#define USHORT      unsigned short
#define VOID        void
#define STATIC      static
#define CONST       const

extern INT Exec_Shell(CONST CHAR* pcCmd, CHAR *pcOutBuf, INT iLen);

#endif

日志功能

/* log.c */
#include "log.h"

VOID LogWright(CHAR *pcModule, CHAR *pcFile, CHAR *pcFunc, INT iLine, CONST CHAR *pcFormat, ...)
{
    va_list argList = {0};
    CHAR szLogTemp[MAX_LOG_SIZE] = {0};
    CHAR szLogHeader[256] = {0};
    CHAR szFileName[64] = {0};
    FILE *fpLogFile;
    CHAR szTime[64] = {0};
    INT iRes = 0;
    struct tm *stNowTime;
    time_t nowTime;

    time(&nowTime);
    stNowTime = localtime(&nowTime);
    sprintf(szFileName, "../log/%04d%02d%02d%s.log", stNowTime->tm_year + 1900, stNowTime->tm_mon + 1, stNowTime->tm_mday, pcModule);
    sprintf(szTime, "%d-%d-%d %d:%d:%d", stNowTime->tm_year + 1900, stNowTime->tm_mon + 1, stNowTime->tm_mday, stNowTime->tm_hour, stNowTime->tm_min, stNowTime->tm_sec);
    va_start(argList, pcFormat);    
    vsnprintf(szLogTemp, MAX_LOG_SIZE, pcFormat, argList);
    va_end(argList);
    snprintf(szLogHeader, sizeof(szLogHeader), "[%s]  [FILE: %s]  [FUNC: %s]  [LINE: %d] ------ ", szTime, pcFile, pcFunc, iLine);
    fpLogFile = fopen(szFileName, "a+");
    if(NULL == fpLogFile)
    {
        printf("FILE:tcp_client_log.c LINE:%d fopen %s error!\r\n", __LINE__, szFileName);
        return;
    }
    fwrite(szLogHeader, 1, strlen(szLogHeader), fpLogFile);
    fwrite(szLogTemp, 1, strlen(szLogTemp), fpLogFile);
    fclose(fpLogFile);
}
/* log.h */
#ifndef _LOG_H_
#define _LOG_H_

#include "../../common/common.h"

#define MAX_LOG_SIZE    4096

#define MODULE_TCPSERVER    "tcp_server"
#define MODULE_TCPCLIENT    "tcp_client"

#define SaveLog(module, format, ...)\
{\
    LogWright((CHAR *)module, (CHAR *)__FILE__, (CHAR *)__FUNCTION__, (INT)__LINE__, format, ##__VA_ARGS__);\
}

extern VOID LogWright(CHAR *pcModule, CHAR *pcFile, CHAR *pcFunc, INT iLine, CONST CHAR *pcFormat, ...);

#endif
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TCP协议服务端与客户端 的相关文章

  • 【Docker】Docker安装telnet

    文章目录 1 概述 1 概述 在使用docker容器时 有时候里边没有安装telnet 敲vim命令时提示说 telnet command not found 这个时候就需要安装vim 可是当你敲apt get install telnet
  • error LNK2019: 无法解析的外部符号 Netbios,该符号在函数 “unsigned char * __cdecl getMACAddress(unsigned char * cons

    我已经正确的加了库 头文件也能找到了 但是还是出现这个问题 说明还是库有问题 原因是我加入的是dcmtk库 是通信有关的 所以还需要在头文件位置加上如下的代码 pragma comment lib netapi32 lib
  • 元数据编辑器--(坑集锦)

    概述 Angular中的输入输出是通过注解 Input和 Output来标识 它位于组件控制器的属性上方 输入输出针对的对象是父子组件 我借鉴的博客地址 https segmentfault com a 1190000007890167 1
  • 人像抠图学习笔记

    目录 人脸分割BiseNetV2 u2net 人脸分割BiseNetV2 宣传的 BiSeNet V2出来了 72 6 的mIOU 156FPS的速度 让分割飞起来 模型30多m TensorFlow平台的 cpu版时间80ms 人脸抠图
  • 两个排序后数组中是否存在相同数字

    因为两个数组都是排好序的 所以只要一次遍历就行了 首先设两个下标 分别初始化为两个数组的起始地址 依次向前推进 推进的规则是比较两个数组中的数字 小的那个数组的下标向前推进一步 直到任何一个数组的下标到达数组末尾时 如果这时还没碰到相同的数

随机推荐

  • Linux下的find指令

    一 概述 因为Linux下面一切皆文件 经常需要搜索某些文件来编写 所以对于linux来说find是一条很重要的命令 linux下面的find指令用于在目录结构中搜索文件 并执行指定的操作 它提供了相当多的查找条件 功能很强大 在不指定查找
  • 第23章组织通用管理

    组织通用管理是项目管理的关键前提和基础 它为项目管理提供思想路线和基本原则与方法 项目管理则是通用管理方法在特定场景下的具体表现 在把项目管理方法运用于实际工作的时候总会表现其通用的方法 反过来说 通用的方法又必定会支配和制约着人们对项目管
  • 理解 Linux 网络栈:Linux 网络协议栈简单总结

    1 Linux 网络路径 1 1 发送端 1 1 1 应用层 1 Socket 应用层的各种网络应用程序基本上都是通过 Linux Socket 编程接口来和内核空间的网络协议栈通信的 Linux Socket 是从 BSD Socket
  • Window10文件在另一个程序中打开无法删除

    1 打开任务管理 点详细信息 2 打开性能 gt 3 打开下方的 资源监视器 4 句柄中输入文件名 5 鼠标右键结束进程 就可以删除文件啦
  • matlab判断cell为空,问与答1:在VBA代码中如何判断单元格是否为空?

    问 如下图所示的工作表 我希望使用VBA代码将空行的背景色设置为灰色 以便于查看 即将上半部分的工作表变为下半部分的样式 我需要判断某行的单元格为空 然后将该行相应的单元格背景色设置为灰色 如何判断单元格是否为空 答 先看看实现所需效果的代
  • 普通人可以做的七个小众副业,让你告别死工资

    现在有什么副业又简单又可以赚得一定的收入呢 当然是有的 下面分享七个适合普通人操作的七个小众副业 1 手工制品 现在手工制品越来越贵 可以做的种类也很多 比如粘土 针织 滴胶 奶油 手机壳 发夹之类的 又是兴趣 又能赚钱 一举两得 可以在一
  • OPF 难解case

    14bus case 当前线路功率极限为Slmax 调整为0 89 Slmax OPF收敛 调整为0 93 1 0001 Slmax OPF不收敛 调整为1 1 Slmax OPF 收敛 其实整个计算过程中 line flow 是not a
  • 数据结构中的顺序表和链表

    目录 1 顺序表 1 1 存储结构 1 2 顺序表特点 1 3 顺序表应用场景 2 链表 2 1 存储结构 最近在复习数据结构中的线性表 下面总结一下顺序表和链表的区别 1 顺序表 线性表的顺序存储称为顺序表 顺序表使得逻辑地址连续的元素在
  • 深度学习之注意力机制详解(Attention)

    深度学习之注意力机制详解 前言 一 自注意力机制 self Attention 二 代码 前言 深度学习attention机制是对人类视觉注意力机制的仿生 本质上是一种资源分配机制 生理原理就是人类视觉注意力能够以高分辨率接收于图片上的某个
  • PCB设计误区-电容的布局布线-电源是不是必须从滤波电容进入芯片管脚(2)

    PCB设计误区 电容的布局布线 电源是不是必须从滤波电容进入芯片管脚 2
  • ubuntu root密码

    Ubuntu root用户默认是禁止的 需要手动打开才行事实上ubuntu下的所有操作都用不到root用户 由于sudo的合理使用 避免了Ubuntu root用户下误操作而产生的毁灭性问题Ubuntu root账号启用方法 其实我个人认为
  • 梅露可物语虚拟服务器,【图片】【萌新】主界面的使用方法(零基础版)【梅露可物语日服吧】_百度贴吧...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 那下面主要讲讲梅露可的货币们 1 钻石 钻石的主要用途有三个 一 抽抽抽 二 碎了这个钻来回复你的ap 三 战斗时候被人打败了有时可以用钻石复活 不过第三个基本是都不用的 因为两瓶元气水或两瓶勇
  • 使用python的retrying库处理尝试多次请求

    功能 一般装饰器api 特定的停止条件 限制尝试次数 特定的等待条件 每次尝试之间的指数增长的时间等待 自定义的异常进行尝试 自定义的异常进行尝试返回结果 最简单的一个使用方法是无论有任何异常出现 都会一直重新调用一个函数 方法 直到返回一
  • js 金额千分位转换

    1 数字转千分位 默认返回当前数字千分位格式 参数说明 number 要格式化的数字 decimals 保留几位小数 dec point 小数点符号 thousands sep 千分位符号 roundtag 舍入参数 默认 ceil 向上取
  • javaWeb,servlet,jsp

    1 servlet是什么 servlet是一种javaEE规范 遵循servlet规范的web应用可以放到不同的web服务器中运行 servlet规范包括 规范了接口 规范了类 规范了一个web应用中应该有哪些配置文件 规范了一个web应用
  • 第十五章 文件读写

    第十五章 文件读写 常见的字符编码格式 python的解释器使用的Unicode 内存 py文件在磁盘上使用的是utf 8存储 外存 对文件的操作 写入文件可以用write 和writelines 读文件可以用read readline 和
  • Vue基础知识总结 5:vue实现树形结构

    目录 一 前言 二 代码实例 1 数据库设计 2 实体类 3 controller 4 service 5 前端 一 前言 开发过程中 涉及到多级菜单的应用 树形结构比较常见 今天就做了一个Spring Boot Vue Element U
  • css鼠标移入img实现放大变暗加显示文字(注意控制自己层级关系)

    效果图 移前 移后 1 变暗方案 img hover filter brightness 50 transform scale 1 2 opacity 1 2文字显示 原始 p opacity 0 font size 25px border
  • RGB颜色表

    RGB色彩模式 也翻译为 红绿蓝 比较少用 是工业界的一种颜色标准 是通过对红 R 绿 G 蓝 B 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的 RGB即是代表红 绿 蓝三个通道的颜色 这个标准几乎包括了人类视力所能感知的
  • TCP协议服务端与客户端

    一 TCP IP协议简介 什么是TCP IP TCP IP协议是一种用于因特网的通信协议 TCP指传输控制协议 Transmission Control Protocol IP指网际协议 Internet Protocol TCP IP协议