当前位置: 首页 > news >正文

《Linux C/C++服务器开发实践》之第4章 TCP服务器编程

《Linux C/C++服务器开发实践》之第4章 TCP服务器编程

    • 4.1 套接字的基本概念
    • 4.2 网络程序的架构
    • 4.3 IP地址的格式转换
        • 4.1.c
    • 4.4 套接字的类型
    • 4.5 套接字地址
      • 4.5.1 通用socket地址
      • 4.5.2 专用socket地址
      • 4.5.3 获取套接字地址
        • 4.2.c
    • 4.6 主机字节序和网络字节序
        • 4.3.c
    • 4.7 协议族和地址族
    • 4.8 TCP套接字编程的基本步骤
    • 4.9 TCP套接字编程的相关函数
      • 4.9.1 BSD socket的头文件
      • 4.9.2 socket函数
      • 4.9.3 bind函数
      • 4.9.4 listen函数
      • 4.9.5 accept函数
      • 4.9.6 connect函数
      • 4.9.7 send函数
      • 4.9.8 recv函数
      • 4.9.9 close函数
    • 4.10 简单的TCP套接字编程
        • 4.4.server.c
        • 4.4.client.c
        • 4.5.c
    • 4.11 深入理解TCP编程
      • 4.11.1 数据发送和接收涉及的缓冲区
      • 4.11.2 TCP数据传输的特点
      • 4.11.3 数据发送的六种情形
      • 4.11.4 数据接收时的情形
      • 4.11.5 一次请求响应的数据接收
        • 4.6.server.c
        • 4.6.client.c
      • 4.11.6 多次请求响应的数据接收
        • 4.7.server.c
        • 4.7.client.c
        • 4.8.c
        • 4.9.server.c
        • 4.9.client.c
    • 4.12 I/O控制命令
        • 4.10.c
    • 4.13 套接字选项
      • 4.13.1 基本概念
      • 4.13.2 选项的级别
      • 4.13.3 获取套接字选项
        • 4.11.c
        • 4.12.c
        • 4.13.c
      • 4.13.4 设置套接字选项
        • 4.14.c

4.1 套接字的基本概念

套接字是TCP/IP网络编程中的基本操作单元,不同主机的进程之间的相互通信的端点。
socket是在应用层和传输层之间的一个抽象层,它把TCP/IC层复杂的操作抽象为几个简单的接口,供应用层调用已实现进程在网络中通信。

4.2 网络程序的架构

B/S(Browser/Server,浏览器/服务器)架构,用户只需要浏览器就行,主要逻辑在服务器完成,减轻了客户端的升级和维护的工作量。

C/S(Client/Server,客户机/服务器)架构,客户端和服务端安装不同应用软件,客户端软件安装或升级比较复杂,维护成本大,可以充分利用两端的硬件能力,较为合理的分配任务。

客户机和服务器间的通信过程:
(1)客户机向服务器提出一个请求。
(2)服务器收到客户机的请求,进行分析处理。
(3)服务器将处理的结果返回给客户机。

4.3 IP地址的格式转换

#include <arpa/inet.h>
//字符串IP地址转换为网络字节序存储在addr中,并返回该网络字节序表示的无符号整数。
//失败:返回0
int inet_aton(const char *IP, struct in_addr *addr);//返回网络字节序
//uint32,失败-1
in_addr_t inet_addr(const char* cp);//及时复制返回的字符串
char *inet_ntoa(struct in_addr in);
#include <arpa/inet.h>
#include <stdlib.h>
#include <iostream>int main()
{char IP[] = "159.12.8.109";in_addr address;int number = inet_aton(IP, &address);//将点分十进制的IP地址转化为二进制的网络字节序if(number == 0){std::cerr<<"error IP!";exit(1);}std::cout << number << std::endl;std::cout << inet_ntoa(address) << std::endl;//将网络字节序地址转化为点分十进制表示形式return 0;
}
4.1.c
#include <stdio.h>
#include <arpa/inet.h>int main()
{in_addr_t dwIP = inet_addr("172.16.2.6");struct in_addr ia;ia.s_addr = dwIP;printf("ia.s_addr = %#x\n", ia.s_addr);printf("real_ip = %s\n", inet_ntoa(ia));return 0;
}

4.4 套接字的类型

(1)流套接字(SOCK_STREAM)
用于提供面向连接的、可靠的数据传输服务,无数据边界(收发次数不一致),可保证数据能够无差别、无重复发送,并按顺序接收(因为使用了传输控制协议即TCP)。

(2)数据报套接字(SOCK_DGRAM)
提供无连接的服务,不保证数据传输的可靠性,有数据边界(数据报收发次数一致),数据传输过程中可能丢失或重复,且无法保证接收数据有序。(使用UDP传输)

(3)原始套接字(SOCK_RAW)
允许对较低层次的协议(IP、ICMP等)直接访问,常用于检验新的协议实现,或者访问现有服务中配置的新设备。
能够控制网络底层传输机制,所以可以应用原始套接字操纵网络层和传输层应用。接收ICMP、IGMP协议包,接收TCP/IP栈不能处理的IP包,发送自定义报头或自定义协议的IP包。
能够读写内核没有处理的IP数据报。

4.5 套接字地址

包含IP地址和端口信息,识别主机及进程。

4.5.1 通用socket地址

表示大多数网络地址,用于socket API函数中。

struct sockaddr{sa_family_t sa_family;char sa_data[14];
};

sa_family_t:地址族或协议族类型

  • PF_UNIX: UNIX本地域协议族
  • PF_INET: IPv4协议族
  • PF_INET6: IPv6协议族
  • AF_UNIX: UNIX本地域地址族
  • AF_INET: IPv4地址族
  • AF_INET: IPv6地址族

sa_data:存放具体的地址数据(IP和端口)

协议族地址的含义和长度
PF_INET32位IPV4地址和16位端口号,共6字节
PF_INET6128位IPv6地址、16位端口号、32位流标识和32位范围ID,共26字节
PF_UNIX文件全路劲名,最大长度可达108字节

4.5.2 专用socket地址

不同协议族定义的不同socket地址结构体,各个信息用不同字段表示。
一般强制转换为通用地址结构使用。

/* Structure describing an Internet socket address.  */
struct sockaddr_in{__SOCKADDR_COMMON (sin_);in_port_t sin_port;			/* Port number.  */struct in_addr sin_addr;		/* Internet address.  *//* Pad to size of `struct sockaddr'.  */unsigned char sin_zero[sizeof (struct sockaddr)- __SOCKADDR_COMMON_SIZE- sizeof (in_port_t)- sizeof (struct in_addr)];};/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr{in_addr_t s_addr;};
#if !__USE_KERNEL_IPV6_DEFS
/* Ditto, for IPv6.  */
struct sockaddr_in6{__SOCKADDR_COMMON (sin6_);in_port_t sin6_port;	/* Transport layer port # */uint32_t sin6_flowinfo;	/* IPv6 flow information */struct in6_addr sin6_addr;	/* IPv6 address */uint32_t sin6_scope_id;	/* IPv6 scope-id */};
#endif /* !__USE_KERNEL_IPV6_DEFS */#if !__USE_KERNEL_IPV6_DEFS
/* IPv6 address */
struct in6_addr{union{uint8_t	__u6_addr8[16];uint16_t __u6_addr16[8];uint32_t __u6_addr32[4];} __in6_u;
#define s6_addr			__in6_u.__u6_addr8
#ifdef __USE_MISC
# define s6_addr16		__in6_u.__u6_addr16
# define s6_addr32		__in6_u.__u6_addr32
#endif};
#endif /* !__USE_KERNEL_IPV6_DEFS */

4.5.3 获取套接字地址

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
//成功0,失败-1
//socklen_t addrlen = sizeof(struct sockaddr_in);

getsockname获取本地套接字地址的情况:

  • 本地套接字已bind地址
  • 本地套接字已connet到远程,内核会分配地址
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
//成功0,失败-1
//socklen_t addrlen = sizeof(struct sockaddr_in);
4.2.c
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>int main()
{int sfp = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sfp){printf("socket() fail!\n");return -1;}printf("socket() ok!\n");char on = 1;setsockopt(sfp, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));struct sockaddr_in serv = {0};int serv_len = sizeof(serv);printf("ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));getsockname(sfp, (struct sockaddr *)&serv, (socklen_t *)&serv_len);printf("ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));unsigned short portnum = 10051;struct sockaddr_in s_add;memset(&s_add, 0, sizeof(struct sockaddr_in));s_add.sin_family = AF_INET;s_add.sin_addr.s_addr = inet_addr("127.0.0.1");s_add.sin_port = htons(portnum);if (-1 == bind(sfp, (struct sockaddr *)(&s_add), sizeof(struct sockaddr))){printf("bind() fail: %d!\n", errno);return -1;}printf("bind() ok!\n");getsockname(sfp, (struct sockaddr *)&serv, (socklen_t *)&serv_len);printf("ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));return 0;
}

4.6 主机字节序和网络字节序

  • 小端字节序Little Endian
    底地址存放低字节

大端字节序Big Endian(网络字节序)
底地址存放高字节

uint32_t主机字节序转网络字节序
htonl
uint16_t主机字节序转网络字节序
htonsuint32_t网络字节序转主机字节序
ntohl
uint16_t网络字节序转主机字节序
ntohs
4.3.c
#include <iostream>
using namespace std;int main()
{int nNum = 0x12345678;char *p = (char *)&nNum;if (*p == 0x12)cout << "This machine is big endian." << endl;elsecout << "This machine is small endian." << endl;return 0;
}

4.7 协议族和地址族

  • 协议族
    不同协议的集合,宏以PF_开头,PROTOCOL FAMILY

  • 地址族
    协议族所使用的地址集合(不同网络协议使用不同网络地址),宏以AF_开头,Address Family

地址族和协议族的值一样,都用来标识不同的一套协议。

4.8 TCP套接字编程的基本步骤

  • 服务器编程步骤:
    一、创建套接字,socket函数
    二、绑定套接字到IP地址和端口,bind函数
    三、套接字设置为监听模式并等待连接请求,listen函数
    四、请求到来时,接受连接请求,返回对应连接的套接字,accept函数
    五、用该连接套接字同客户端通信,send或recv函数,通信结束关闭,closesocket函数
    六、监听套接字等待其他客户端的连接
    七、推出服务器程序,关闭监听套接字,closesocket函数

客户端编程步骤:
一、创建套接字,socket函数
二、向服务器发出请求连接,connect函数
三、同服务器端通信,send或recv函数,
四、通信结束关闭,closesocket函数

4.9 TCP套接字编程的相关函数

4.9.1 BSD socket的头文件

  • <sys/socket.h>:核心函数和数据结构的声明
  • <netinet/in.h>:地址族和协议族,IP地址和端口号等
  • <bits/socket.h>:地址族和协议族的宏定义
  • <arpa/inet.h>:IP地址相关函数
  • <netdb.h>:协议名和主机名转化为数字的函数
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

4.9.2 socket函数

创建套接字,并分配系统资源

int socket(int domain, int type, int protocol);
//AF_INET
//SOCK_STREAM, SOCK_DGRAM, SOCK_RAW
//IPPROTO_TCP, IPPROTO_UDP, 0
//默认都是阻塞

4.9.3 bind函数

本地地址信息关联到套接字上。

int bind(int sockfd, const struct* addr, socklen_t addrlen);
//成功0,失败-1,errno获取错误码
sockaddr_in in;
in_addr_t ip = inet_addr("192.168.13.25");
if(ip != -1)in.sin_addr.s_addr  = ip;//#define INADDR_ANY ((in_addr_t) 0x00000000)
in.sin_addr.s_addr = htonl(INADDR_ANY);//errno,98,端口占用、未释放或程序未正常结束

4.9.4 listen函数

套接字处于监听状态。

int listen(int sockfd, int backlog);
//成功0,失败-1

4.9.5 accept函数

从监听套接字的客户连接请求队列获取客户端请求,并创建新的套接字来和客户端通信。

int accept(int sockfd, struct sockaddr *addr, socklen_t * addrlen);
//失败-1

4.9.6 connect函数

请求与监听套接字建立连接。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//成功0,失败-1

非阻塞时,可设置连接超时时间,通过error中EINRPOCESS(Operation now in progress)判断。

4.9.7 send函数

发送数据,复制到套接字的发送缓冲区。

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//成功返回发送拷贝字节数,对方关闭返回0,错误-1

TCP有发送缓冲区,UDP无发送缓冲区。

非阻塞,可利用error变量EAGAIN

send用于有连接的套接字。

sendto和sendmsg用于有或无连接的套接字。

4.9.8 recv函数

接收数据.

ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
//成功返回接收字节数,对方关闭返回0,错误-1,errno是EINTR、EWOULDBLOCK或EAGAIN时连接正常

recvfrom也能接收数据。

4.9.9 close函数

关闭套接字

#include <unistd.h>
int close(int fd);
//成功0,失败-1

4.10 简单的TCP套接字编程

4.4.server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>int main()
{int sockSrv = socket(AF_INET, SOCK_STREAM, 0);char on = 1;setsockopt(sockSrv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));struct sockaddr_in addrSrv;memset(&addrSrv, 0, sizeof(struct sockaddr_in));addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);if (-1 == bind(sockSrv, (struct sockaddr *)&addrSrv, sizeof(struct sockaddr))){printf("bind() fail: %d!\n", errno);return -1;}const int len = sizeof(struct sockaddr_in);struct sockaddr_in serv;getsockname(sockSrv, (struct sockaddr *)&serv, (socklen_t *)&len);printf("server has started, ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));listen(sockSrv, 5);struct sockaddr_in addrClient;while (1){printf("--------wait for client-----------\n");int sockConn = accept(sockSrv, (struct sockaddr *)&addrClient, (socklen_t *)&len);char sendBuf[100];sprintf(sendBuf, "Welcome client(%s: %d) to Server!", inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);char recvBuf[100];recv(sockConn, recvBuf, 100, 0);printf("Receive client's msg: %s\n", recvBuf);close(sockConn);/*puts("continue to listen?(y/n)");char ch[2];scanf("%s", ch, 2);if (ch[0] != 'y')break;*/}close(sockSrv);return 0;
}
4.4.client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>int main()
{int sockClient = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addrSrv;addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);int err = connect(sockClient, (struct sockaddr *)&addrSrv, sizeof(struct sockaddr));if (-1 == err){printf("Failed to connect to the server.Please check whether the server is started\n");return 0;}char recvBuf[100] = {0};recv(sockClient, recvBuf, 100, 0);printf("receive server's msg: %s\n", recvBuf);char msg[] = "hi,server";send(sockClient, msg, strlen(msg) + 1, 0);close(sockClient);return 0;
}
4.5.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>#define BUFFER_SIZE 512unsigned long GetTickCount()
{struct timeval tv;if (gettimeofday(&tv, NULL) != 0)return 0;return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}int main()
{struct sockaddr_in server_address;memset(&server_address, 0, sizeof(server_address));server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = inet_addr("192.168.0.88");server_address.sin_port = htons(13334);int sock = socket(PF_INET, SOCK_STREAM, 0);assert(sock >= 0);long t1 = GetTickCount();int ret = connect(sock, (struct sockaddr *)&server_address, sizeof(server_address));if (ret == -1){long t2 = GetTickCount();printf("connect() failed: %d\n", ret);printf("time used: %ldms\n", t2 - t1);if (errno == EINPROGRESS)printf("unblock mode ret code...\n");}elseprintf("ret code is: %d\n", ret);close(sock);return 0;
}

4.11 深入理解TCP编程

4.11.1 数据发送和接收涉及的缓冲区

应用缓冲区和TCP套接字缓冲区(内核缓冲区)。

4.11.2 TCP数据传输的特点

一、字节流,无消息边界。
二、send后并不立即发送数据,内核控制。
三、数据发送速度,网络状态决定。
四、控制数据真实发送,网络状态决定。
五、recv时并不知道真实已接收多少数据。

4.11.3 数据发送的六种情形

假设调用两次send,发送数据A和数据B。(send(A),send(B)),真实发送情况:
一、网络情况良好,未受发送窗口、拥塞窗口和TCP最大传输单元影响,A、B变成两个数据段发送。
二、网络不好,发送A被延迟,A、B数据合并,且长度未超过窗口大小和最大传输单元。AB合并发送一次。
三、网络不好,发送A被延迟,A、B数据合并,且长度超过窗口大小或最大传输单元。AB合并发送(AB1、B2)。
四、网络不好,发送A被延迟,A、B数据合并,且长度超过窗口大小或最大传输单元。AB合并发送(A1、A2B)。
五、接收窗口小,AB分成多份发送。
六、发送错误,失败。

4.11.4 数据接收时的情形

  1. 接收到本次达到接收端的全部数据
  2. 接收到达到接收端的部分数据
  3. 没有收到数据

send与实际发送次数无关,send与recv次数无关。

4.11.5 一次请求响应的数据接收

接收到全部数据后断开连接,通过recv返回0判断发送方数据发送完毕。

4.6.server.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>#define BUF_LEN 300typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;int main()
{int sockSrv = socket(AF_INET, SOCK_STREAM, 0);assert(sockSrv >= 0);char on = 1;setsockopt(sockSrv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));SOCKADDR_IN addrSrv;addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));listen(sockSrv, 5);const int len = sizeof(SOCKADDR);SOCKADDR_IN addrClient;while (1){printf("--------wait for client-----------\n");int sockConn = accept(sockSrv, (SOCKADDR *)&addrClient, (socklen_t *)&len);char sendBuf[100] = "";for (int i = 0; i < 10; i++){memset(sendBuf, 0, sizeof(sendBuf));sprintf(sendBuf, "N0.%d Welcome to the server. What is 1 + 1 = ? (client IP: %s, client Port: %d)\n", i + 1, inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));send(sockConn, sendBuf, strlen(sendBuf), 0);}int iRes = shutdown(sockConn, SHUT_WR);if (iRes == -1){printf("shutdown failed with error: %d\n", errno);close(sockConn);return 1;}char recvBuf[BUF_LEN];do{iRes = recv(sockConn, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("Recv %d bytes.\n", iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){printf("The client has closed the connection.\n");}else{printf("recv failed with error: %d\n", errno);close(sockConn);return 1;}} while (iRes > 0);close(sockConn);/*puts("Continue monitoring?(y/n)");char ch[2];scanf("%s", ch, 2);if (ch[0] != 'y')break;*/}close(sockSrv);return 0;
}
4.6.client.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>#define BUF_LEN 300typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;int main()
{int sockClient = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);int err = connect(sockClient, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));if (-1 == err){printf("Failed to connect to the server. Please check whether the server is started\n");return 0;}char recvBuf[BUF_LEN];int iRes;do{iRes = recv(sockClient, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("\nRecv %d bytes:", iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){puts("The server has closed the send connection.\n");}else{printf("recv failed:%d\n", errno);close(sockClient);return 1;}} while (iRes > 0);char sendBuf[100];for (int i = 0; i < 10; i++){memset(sendBuf, 0, sizeof(sendBuf));sprintf(sendBuf, "N0.%d I'm the client, 1+1=2\n", i + 1);send(sockClient, sendBuf, strlen(sendBuf) + 1, 0);}puts("Sending data to the server is completed.");close(sockClient);return 0;
}

4.11.6 多次请求响应的数据接收

  1. 定长数据的接收
4.7.server.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>#define BUF_LEN 300typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;int main()
{int sockSrv = socket(AF_INET, SOCK_STREAM, 0);assert(sockSrv >= 0);char on = 1;setsockopt(sockSrv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));SOCKADDR_IN addrSrv;addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));listen(sockSrv, 5);const int len = sizeof(SOCKADDR);SOCKADDR_IN addrClient;char sendBuf[111];char recvBuf[BUF_LEN];while (1){printf("--------wait for client-----------\n");int sockConn = accept(sockSrv, (SOCKADDR *)&addrClient, (socklen_t *)&len);printf("--------client comes-----------\n");memset(sendBuf, 'a', 111);for (int cn = 0; cn < 50; cn++){if (cn == 49)sendBuf[110] = 'b';send(sockConn, sendBuf, 111, 0);}int iRes;do{iRes = recv(sockConn, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("\nRecv %d bytes:", iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){printf("The client closes the connection.\n");}else{printf("recv failed with error: %d\n", errno);close(sockConn);return 1;}} while (iRes > 0);close(sockConn);/*puts("Continue monitoring?(y/n)");char ch[2];scanf("%s", ch, 2);if (ch[0] != 'y')break;*/}close(sockSrv);return 0;
}
4.7.client.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>#define BUF_LEN 250typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;int main()
{int sockClient = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);int err = connect(sockClient, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));if (-1 == err){printf("Failed to connect to the server:%d\n", errno);return 0;}char recvBuf[BUF_LEN];int iRes;int cn = 1;for (int leftlen = 50 * 111; leftlen > 0; leftlen -= iRes){iRes = recv(sockClient, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){puts("\nThe server has closed the send connection.\n");}else{printf("recv failed: %d\n", errno);close(sockClient);return -1;}}/*int leftlen = 50 * 111;while (leftlen > BUF_LEN){iRes = recv(sockClient, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){puts("\nThe server has closed the send connection.\n");}else{printf("recv failed: %d\n", errno);close(sockClient);return -1;}leftlen -= iRes;}if (leftlen > 0){iRes = recv(sockClient, recvBuf, leftlen, 0);if (iRes > 0){printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){puts("\nThe server has closed the send connection.\n");}else{printf("recv failed: %d\n", errno);close(sockClient);return -1;}leftlen -= iRes;}
*/char sendBuf[100];memset(sendBuf, 0, sizeof(sendBuf));sprintf(sendBuf, "Hi, Server, I've finished receiving the data.");send(sockClient, sendBuf, strlen(sendBuf) + 1, 0);puts("Sending data to the server is completed");close(sockClient);return 0;
}
  1. 变长数据的接收
    数据报末尾加结束标识符
    变长消息体前加固定长度的报头,报头内加入消息体长度字段
struct MyData
{int nLen;char data[0];
};
struct MyData* p = (struct MyData*)malloc(sizeof(struct MyData)+strlen(str));
4.8.c
#include <cstdio>
#include <iostream>
#include <string.h>
using namespace std;struct MyData
{int nLen;char data[0];
};int main()
{cout << "Size of MyData: " << sizeof(MyData) << endl;char str[10] = "123456";int nLen = sizeof(str);MyData *myData = (MyData *)malloc(sizeof(MyData) + nLen);myData->nLen = nLen;memcpy(myData->data, str, nLen);cout << "myData's Data is: " << myData->data << endl;cout << "Size of MyData: " << sizeof(MyData) << endl;free(myData);return 0;
}
4.9.server.c
#include <cstdio>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <malloc.h>#define BUF_LEN 300typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;struct MyData
{int nLen;char data[0];
};int main()
{int sockSrv = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));listen(sockSrv, 5);SOCKADDR_IN addrClient;int len = sizeof(SOCKADDR);int cn = 5550;struct MyData *mydata;int iRes;char recvBuf[BUF_LEN];while (1){printf("--------wait for client-----------\n");int sockConn = accept(sockSrv, (SOCKADDR *)&addrClient, (socklen_t *)&len);printf("--------client comes-----------\n");mydata = (MyData *)malloc(sizeof(MyData) + cn);mydata->nLen = htonl(cn);memset(mydata->data, 'a', cn);mydata->data[cn - 1] = 'b';send(sockConn, (char *)mydata, sizeof(MyData) + cn, 0);free(mydata);do{iRes = recv(sockConn, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("\nRecv %d bytes: ", iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){printf("\nThe client has closed the connection.\n");}else{printf("recv failed with error: %d\n", errno);close(sockConn);return 1;}} while (iRes > 0);close(sockConn);/*puts("Continue monitoring?(y/n)");char ch[2];scanf("%s", ch, 2);if (ch[0] != 'y')break;*/}close(sockSrv);return 0;
}
4.9.client.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <malloc.h>#define BUF_LEN 250typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;int main()
{int sockClient = socket(AF_INET, SOCK_STREAM, 0);SOCKADDR_IN addrSrv;addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(8000);int err = connect(sockClient, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));if (-1 == err){printf("Failed to connect to the server:%d\n", errno);return 0;}int leftlen;int iRes = recv(sockClient, (char *)&leftlen, sizeof(int), 0);leftlen = ntohl(leftlen);printf("Need to receive %d bytes data.\n", leftlen);char recvBuf[BUF_LEN];int cn = 1;for (; leftlen > 0; leftlen -= iRes){if (leftlen < BUF_LEN)iRes = recv(sockClient, recvBuf, leftlen, 0);elseiRes = recv(sockClient, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){puts("\nThe server has closed the send connection.\n");}else{printf("recv failed: %d\n", errno);close(sockClient);return -1;}}/*while (leftlen > BUF_LEN){iRes = recv(sockClient, recvBuf, BUF_LEN, 0);if (iRes > 0){printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){puts("\nThe server has closed the send connection.\n");}else{printf("recv failed: %d\n", errno);close(sockClient);return -1;}leftlen -= iRes;}if (leftlen > 0){iRes = recv(sockClient, recvBuf, leftlen, 0);if (iRes > 0){printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);for (int i = 0; i < iRes; i++)printf("%c", recvBuf[i]);printf("\n");}else if (iRes == 0){puts("\nThe server has closed the send connection.\n");}else{printf("recv failed: %d\n", errno);close(sockClient);return -1;}leftlen -= iRes;}*/char sendBuf[100];memset(sendBuf, 0, sizeof(sendBuf));sprintf(sendBuf, "I'm the client. I've finished receiving the data.");send(sockClient, sendBuf, strlen(sendBuf) + 1, 0);puts("Sending data to the server is completed");close(sockClient);return 0;
}

4.12 I/O控制命令

设置套接字的工作模式(阻塞或非阻塞),获取套接字I/O操作的参数信息。

#include <sys/ioctl.h>
int ioctl(int fd, int request, ...);
//成功0,失败-1,errno错误码

I/O控制命令request:

  • FIONBIO
    阻塞
  • FIONREAD
    流套接字,recv一次可读入数据量;数据报套接字,第一个数据报大小;缓冲区大小。
  • FIOASYNC
    异步
int iMode = 0;
ioctl(m_socket, FIONBIO, &iMode); //阻塞模式int num = 0;
ioctl(0, FIONREAD, &iMode); //标准输入缓冲区字节数
4.10.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>unsigned long GetTickCount()
{struct timeval tv;if (gettimeofday(&tv, NULL) != 0)return 0;return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}int main()
{char ip[] = "192.168.0.88";in_addr_t dwIP = inet_addr(ip);int port = 13334;struct sockaddr_in server_address;memset(&server_address, 0, sizeof(server_address));server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = dwIP;server_address.sin_port = htons(port);int sock = socket(PF_INET, SOCK_STREAM, 0);assert(sock >= 0);long t1 = GetTickCount();int ret = connect(sock, (struct sockaddr *)&server_address, sizeof(server_address));printf("connect ret code is: %d\n", ret);if (ret == -1){long t2 = GetTickCount();printf("time used: %ldms\n", t2 - t1);printf("connect() failed...\n");if (errno == EINPROGRESS)printf("unblock mode ret code...\n");}elseprintf("ret code is: %d\n", ret);int argp = 1;int res = ioctl(sock, FIONBIO, &argp);if (-1 == res){printf("Error at ioctlsocket(): %d\n", errno);return -1;}puts("\nAfter setting non blocking mode:");/*memset(&server_address, 0, sizeof(server_address));server_address.sin_family = AF_INET;server_address.sin_addr.s_addr = dwIP;server_address.sin_port = htons(port);*/t1 = GetTickCount();ret = connect(sock, (struct sockaddr *)&server_address, sizeof(server_address));printf("connect ret code is: %d\n", ret);if (ret == -1){long t2 = GetTickCount();printf("time used: %ldms\n", t2 - t1);if (errno == EINPROGRESS)printf("unblock mode errno: %d\n", errno);}elseprintf("ret code is: %d\n", ret);close(sock);return 0;
}

4.13 套接字选项

4.13.1 基本概念

设置或获取套接字属性

4.13.2 选项的级别

适用范围或适用对象,有些选项针对特定协议,有些选项适用所有类型套接字。
SO_TYPE
SO_SNDBUF
SO_REUSEADDR
SO_RCVBUF
SO_ERROR

4.13.3 获取套接字选项

#include <sys/types.h>
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
//成功0,失败-1,errno错误码
//EBADF:sockfd不是有效文件描述符
//EFAULT:optlen太小或optval缓冲区非法
//EINVAL:level未知或非法
//ENOPROTOOPT:选项未知或不被指定协议族支持
//ENOTSOCK:sockfd不是套接字描述符
4.11.c
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>int main()
{int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (s == -1){printf("Error at socket()\n");return -1;}int su = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (s == -1){printf("Error at socket()\n");return -1;}int optVal;int optLen = sizeof(optVal);if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed: %d", errno);elseprintf("Size of stream socket receive buffer: %d bytes\n", optVal);if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed: %d", errno);elseprintf("Size of streaming socket send buffer: %d bytes\n", optVal);if (getsockopt(su, SOL_SOCKET, SO_RCVBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed: %d", errno);elseprintf("Size of datagram socket receive buffer: %d bytes\n", optVal);if (getsockopt(su, SOL_SOCKET, SO_SNDBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed: %d", errno);elseprintf("Size of datagram socket send buffer: %d bytes\n", optVal);return 0;
}
4.12.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>int main()
{int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (s == -1){printf("Error at socket()\n");return -1;}int optVal;int optLen = sizeof(optVal);if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed: %d", errno);else{if (SOCK_STREAM == optVal)printf("The current socket is a stream socket.\n");else if (SOCK_DGRAM == optVal)printf("The current socket is a datagram socket.\n");}int su = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if (su == -1){printf("Error at socket()\n");return -1;}if (getsockopt(su, SOL_SOCKET, SO_TYPE, (char *)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed: %d", errno);else{if (SOCK_STREAM == optVal)printf("The current socket is a stream socket.\n");else if (SOCK_DGRAM == optVal)printf("The current socket is a datagram socket.\n");}return 0;
}
4.13.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>typedef struct sockaddr SOCKADDR;int main()
{int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (s == -1){printf("Error at socket()\n");return -1;}char on = 1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));char ip[] = "127.0.0.1";struct sockaddr_in service;service.sin_family = AF_INET;service.sin_addr.s_addr = inet_addr(ip);service.sin_port = htons(8000);if (bind(s, (SOCKADDR *)&service, sizeof(service)) == -1){printf("bind failed: %d\n", errno);return -1;}int optVal;int optLen = sizeof(optVal);if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&optVal, (socklen_t *)&optLen) == -1)printf("getsockopt failed: %d", errno);elseprintf("Before listening, The value of SO_ACCEPTCONN: %d, The socket is not listening\n", optVal);if (listen(s, 100) == -1){printf("listen failed: %d\n", errno);return -1;}if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&optVal, (socklen_t *)&optLen) == -1){printf("getsockopt failed: %d", errno);return -1;}elseprintf("After listening, The value of SO_ACCEPTCONN: %d, The socket is listening\n", optVal);return 0;
}

4.13.4 设置套接字选项

#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t *optlen);
//成功0,失败-1,errno错误码
4.14.c
#include <stdio.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>typedef struct sockaddr SOCKADDR;int main()
{int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (s == -1){printf("Error at socket()\n");return -1;}char on = 1;setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));char ip[] = "127.0.0.1";struct sockaddr_in service;service.sin_family = AF_INET;service.sin_addr.s_addr = inet_addr(ip);service.sin_port = htons(9900);if (bind(s, (SOCKADDR *)&service, sizeof(service)) == -1){printf("bind failed\n");return -1;}int optVal = 1;int optLen = sizeof(int);if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, (socklen_t *)&optLen) == -1){printf("getsockopt failed: %d", errno);return -1;}elseprintf("After bind, the value of SO_KEEPALIVE: %d\n", optVal);optVal = 1;if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, optLen) != -1)printf("Successful activation of keep alive mechanism.\n");if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, (socklen_t *)&optLen) == -1){printf("getsockopt failed: %d", errno);return -1;}elseprintf("After setting, the value of SO_KEEPALIVE: %d\n", optVal);return 0;
}

相关文章:

《Linux C/C++服务器开发实践》之第4章 TCP服务器编程

《Linux C/C服务器开发实践》之第4章 TCP服务器编程 4.1 套接字的基本概念4.2 网络程序的架构4.3 IP地址的格式转换4.1.c 4.4 套接字的类型4.5 套接字地址4.5.1 通用socket地址4.5.2 专用socket地址4.5.3 获取套接字地址4.2.c 4.6 主机字节序和网络字节序4.3.c 4.7 协议族和地址…...

HCIA---静态路由扩展配置

静态的扩展配置&#xff1a; 1、负载均衡&#xff1a;当访问相同目标&#xff0c;具有多条开销相似路径时&#xff1b;可以让设备将流量拆分后延多条路径同时传输&#xff1b;起到带宽叠加的作用&#xff1b; 2、环回接口-- 创建后&#xff0c;可用于路由器测试TCP/IP协议组件…...

OCP Java17 SE Developers 复习题04

答案 F. Line 5 does not compile. This question is checking to see whether you are paying attention to the types. numFish is an int, and 1 is an int. Therefore, we use numeric addition and get 5. The problem is that we cant store an int in a String variab…...

spark中使用flatmap报错:TypeError: ‘int‘ object is not subscriptable

1、背景描述 菜鸟笔者在运行下面代码时发生了报错&#xff1a; from pyspark import SparkContextsc SparkContext("local", "apple1012")rdd sc.parallelize([[1, 2], 3, [7, 5, 6]])rdd1 rdd.flatMap(lambda x: x) print(rdd1.collect())报错描述如…...

node.js知识系列(5)-每天了解一点

目录 21. RESTful API 设计中的 HTTP 动词22. 中间件链和回调地狱23. Express.js 的 ORM 经验24. 错误处理中间件和 HTTP 状态码25. 事件循环&#xff08;Event Loop&#xff09;在异步编程中的作用26. Node.js 缓存机制27. Node.js 全局对象28. 性能分析和调优经验29. Express…...

Linux服务器(银河麒麟、CentOS 7+、CentOS 7+ 等)修改IP地址

打开终端或控制台&#xff0c;以root或具有sudo权限的用户身份登录。根据你的Linux发行版和网络管理工具的不同&#xff0c;相应的命令可能略有不同。使用以下命令编辑网络配置文件&#xff0c;例如eth0网卡的配置文件&#xff1a; 注意&#xff1a;ifcfg-eth0 可能会有不同的命…...

Mall脚手架总结(四) —— SpringBoot整合RabbitMQ实现超时订单处理

前言 在电商项目中&#xff0c;订单因为某种特殊情况被取消或者超时未支付都是比较常规的用户行为&#xff0c;而实现该功能我们就要借助消息中间件来为我们维护这么一个消息队列。在mall脚手架中选择了RabbitMQ消息中间件&#xff0c;接下来荔枝就会根据功能需求来梳理一下超时…...

python实现图像的直方图均衡化

直方图均衡化是一种用于增强图像对比度的图像处理技术。它通过重新分配图像中的像素值&#xff0c;使得图像的像素值分布更加均匀&#xff0c;增强图像的对比度&#xff0c;从而改善图像的视觉效果。 直方图均衡化的过程如下&#xff1a; 灰度转换&#xff1a;如果图像是彩色…...

哪种烧录单片机的方法合适?

哪种烧录单片机的方法合适&#xff1f; 首先&#xff0c;让我们来探讨一下单片机烧录的方式。虽然单片机烧录程序的具体方法会因为单片机型号、然后很多小伙伴私我想要嵌入式资料&#xff0c;通宵总结整理后&#xff0c;我十年的经验和入门到高级的学习资料&#xff0c;只需一…...

安规电容总结

安规电容 顾名思义&#xff1a;电容即使失效后&#xff0c;也不会漏电或者放电伤人&#xff0c;要符合安全规定 多数高压认证产品都需要。 上图&#xff1a; X电容&#xff1a; Y电容&#xff1a; 区别&#xff1a; 电路示意&#xff1a;...

MyCat分片垂直拆分

场景 在业务系统中 , 涉及以下表结构 , 但是由于用户与订单每天都会产生大量的数据 , 单台服务器的数据 存储及处理能力是有限的 , 可以对数据库表进行拆分 , 原有的数据库表如下。 现在考虑将其进行垂直分库操作&#xff0c;将商品相关的表拆分到一个数据库服务器&#…...

MongoDB bin目录没有mongo.exe命令

MongoDB从6.0版本开始就取消了在Bin目录中加入Compass连接工具&#xff0c;需要大家自行安装。 可以定位到我的文章 链接地址 点击右侧目录的 标题三&#xff1a;MongoDB Compass连接MongoDBMongoDB Compass的安装方法哦~...

Zookeeper分布式一致性协议ZAB源码剖析

文章目录 1、ZAB协议介绍2、消息广播 1、ZAB协议介绍 ZAB 协议全称&#xff1a;Zookeeper Atomic Broadcast&#xff08;Zookeeper 原子广播协议&#xff09;。 Zookeeper 是一个为分布式应用提供高效且可靠的分布式协调服务。在解决分布式一致性方面&#xff0c;Zookeeper 并…...

微软 AR 眼镜新专利:包含热拔插电池

近日&#xff0c;微软在增强现实&#xff08;AR&#xff09;领域进行深入的研究&#xff0c;并申请了一项有关于“热插拔电池”的专利。该专利于2023年10月5日发布&#xff0c;描述了一款采用模块化设计的AR眼镜&#xff0c;其热插拔电池放置在镜腿部分&#xff0c;可以直接替代…...

软件TFN 2K的分布式拒绝攻击(DDos)实战详解

写在前头 本人写这篇博客的目的&#xff0c;并不是我想成为黑客或者鼓励大家做损坏任何人安全和利益的事情。因科研需要&#xff0c;我学习软件TFN 2K的分布式拒绝攻击&#xff0c;只是分享自己的学习过程和经历&#xff0c;有助于大家更好的关注到网络安全及网络维护上。 需要…...

计算机网络第四章——网络层(末)

赌书消得泼茶香当时只道是寻常 文章目录 概述&#xff1a;组播机制是让源计算机一次发送的单个分组可以抵达用一个组地址标识的若干目标主机&#xff0c;并被它们正确接收&#xff0c;组播仅应用于UDP 因特网中的IP组播也使用组播组的概念&#xff0c;每个组都有一个特别分配的…...

Newman基本使用

目录 简介 安装 使用 官网 运行 输出测试报告文件 htmlextra 使用 简介 Newman 是 Postman 推出的一个 nodejs 库&#xff0c;直接来说就是 Postman 的json文件可以在命令行执行的插件。   Newman 可以方便地运行和测试集合&#xff0c;并用之构造接口自动化测试和持续集成…...

左值引用右值引用

文章目录 左值和右值什么是左值什么是右值左值引用与右值引用的比较左值引用总结右值引用的总结&#xff1a; 右值引用使用场景和意义左值引用的使用场景左值引用的短板 右值引用和移动语义解决上面的问题不仅仅有移动构造还有移动赋值 右值引用引用左值及其一些更深入的使用场…...

学习开发一个RISC-V上的操作系统(汪辰老师) — 一次RV32I加法指令的反汇编

前言 &#xff08;1&#xff09;此系列文章是跟着汪辰老师的RISC-V课程所记录的学习笔记。 &#xff08;2&#xff09;该课程相关代码gitee链接&#xff1b; &#xff08;3&#xff09;PLCT实验室实习生长期招聘&#xff1a;招聘信息链接 前置知识 RISC-V 汇编指令编码格式 &a…...

IDEA中点击New没有Java Class

解决办法&#xff1a;右键src&#xff0c;也可以是其他文件名&#xff0c;点击Mark Directory as 点击Sources Root即可...

打造炫酷效果:用Java优雅地制作Excel迷你图

摘要&#xff1a;本文由葡萄城技术团队原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 迷你图是一种简洁而有效的数据可视化方式&#xff0c;常用于展示趋势和变化。它通常由一…...

pycharm设置pyuic和pyrcc

pyuic设置 适合任何虚拟环境&#xff0c;直接用虚拟环境的python解决一切。。。 E:\anaconda3\envs\qt5\python.exe-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py$FileDir$pyrcc设置 E:\anaconda3\envs\qt5\python.exe-m PyQt5.pyrcc_main $FileName$ -o…...

OpenCV6-图形绘制

OpenCV6-图形绘制 1.绘制圆形2.绘制直线3.绘制椭圆4.绘制多边形5.文字生成6.demo 1.绘制圆形 void cv::circle(InputOutputArray img, // 需要绘制圆形的图像Point center, // 圆心坐标int radius, // 半径&#xff0c;单位为像素const Scalar& colo…...

kafka消费者程序日志报错Offset commit failed问题研究

生产环境偶尔会遇到kafka消费者程序日志报错的问题 截取主要日志如下&#xff1a; 2023-10-02 19:35:28.554 {trace: d7f97f70dd693e3d} ERROR[Thread-49:137] ConsumerCoordinator$OffsetCommitResponseHandler.handle(812) - [Consumer clientIdconsumer-1, groupIdcid_yin…...

SpringBoot+原生HTML+MySQL开发的电子病历系统源码

电子病历系统源码 电子病历编辑器源码 云端SaaS服务 电子病历系统&#xff0c;采用 “所见即所得、一体化方式”&#xff0c;协助医生和护士准确、标准、快捷实现病历书写、修改、审阅、打印、体温单浏览、医嘱管理等&#xff0c;是提供病历快速简洁化完成的一系列综合型医生病…...

软件测试/测试开发/人工智能丨聊聊AutoGPT那些事儿

点此获取更多相关资料 简介 在 ChatGPT 问世之后&#xff0c;大家很容易就发现其依然具备一些很难解决的问题&#xff0c;比如&#xff1a; Token 超出限制怎么办&#xff1f;&#xff08;目前最新的 GPT4 支持最多8,192 tokens&#xff09;。如何完全自动化&#xff1f;任务…...

KdMapper扩展实现之SOKNO S.R.L(speedfan.sys)

1.背景 KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动&#xff0c;本文是利用其它漏洞&#xff08;参考《【转载】利用签名驱动漏洞加载未签名驱动》&#xff09;做相应的修改以实现类似功能。需要大家对KdMapper的代码有一定了解。 2.驱动信息 驱动名称spee…...

MATLAB算法实战应用案例精讲-【图像处理】计算机视觉

目录 前言 几个高频面试题目 计算机视觉与图像处理、模式识别、机器学习学科之间的关系 计算机视觉和机器人视觉区别与联系...

docker应用的缓存 docker缓存机制

Docker镜像用作Docker执行程序中的主映像。它们是容器的蓝图&#xff0c;提供了有关如何生成容器的说明。在本文中&#xff0c;我将介绍一些经常被忽视的概念&#xff0c;这些概念将有助于优化Docker镜像开发和构建过程。 让我们从Docker构建过程的简短描述开始。这是通过使用…...

借助 ZooKeeper 生成唯一 UUID

ZooKeeper是一个分布式协调服务&#xff0c;它主要用于在分布式系统中管理和协调各种资源。它本身并不提供生成唯一UUID的功能&#xff0c;但你可以借助ZooKeeper来实现生成唯一UUID的机制。 下面是一种基于ZooKeeper的方法来生成唯一UUID的示例&#xff1a; 在ZooKeeper中创建…...