网络编程学习笔记整理(二)
摘录笔记 《TCP/IP高效编程 改善网络程序的44个技巧》
socket的创建函数
int socket (int domain,int type, int protocol)
参数说明
protocol需要注意 常见有三个选项
SOCK_STREAM 创建TCP socket
SOCK_DGRAM 创建UDP socket
SOCK_RAW 对IP层的数据进行访问 例如监听ICMP 使用此种socket
TCP接收发送函数为 recv send
linux下也可以使用read write函数
其中参数
MSG_OOB 表示发送读取紧急数据
MSG_PEEK 表示查看数据但是不会将其从缓冲中删除 下次依旧可以读取
MSG_DONTROUTE 表示内核绕过通常的选路函数 用于网络诊断
UDP接收发送函数使用 recvfrom sendto
面向连接与无连接的区别
无连接每个数据报是独立主体,相互间没有关联。网络传输中尽力正确传输数据,但是不保证数据不丢失、不乱序、不延迟
面向连接维护多个数据报间的关联,保证不发生乱序,并进行数据报到达的确认,以及超时重传机制
私有地址IP主机与因特网或者其他外网通讯使用NAT( Network Address Translation 网络地址翻译)
分为三种模式
1 静态地址 将私有网络的部分或者所有主机都映射为一个固定的全局分配的地址(少见)
2 地址池 NAT设备有一组全局分配的IP地址可用,会将其中之一动态分配给需要与外部网络对等通讯的主机
3 PAT Port Address Translation 端口地址转换 只有一个全局分配地址时使用此种办法。所有私有地址IP对应全局分配地址IP的一个端口,私有地址IP通过该端口与外部网络通讯
#pragma once #include <WinSock2.h> #include <iostream> #include <WS2tcpip.h> #pragma comment(lib,"WS2_32.lib") #define MAXLINE 1024 #define DEFAULT_IP_ADDR "127.0.0.1" void err_sys(const char* msg) { std::cout << msg << std::endl; exit(-1); } class InitWinSock { public: InitWinSock() { WORD myVersionRequest; WSADATA wsaData; myVersionRequest = MAKEWORD(2, 2); int err = WSAStartup(myVersionRequest, &wsaData); if (err) { exit(-1); } } ~InitWinSock() { WSACleanup(); } }; SOCKET TCPClientSock(const char* ipStr,USHORT port) { SOCKET sockfd; struct sockaddr_in servaddr; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { err_sys("sock error"); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(port); if (inet_pton(AF_INET, DEFAULT_IP_ADDR, &servaddr.sin_addr) <= 0) err_sys("inet_pton error"); if (connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0) err_sys("connect error"); return sockfd; } SOCKET TCPServerSock(USHORT port) { SOCKET sockfd = -1; int rc; struct sockaddr_in local; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { err_sys("sock error"); } local.sin_family = AF_INET; local.sin_port = htons(port); local.sin_addr.s_addr = htonl(INADDR_ANY); rc = bind(sockfd, (struct sockaddr*)&local, sizeof(local)); if (rc < 0) { err_sys("bind call failure"); } rc = listen(sockfd, 5); if (rc) { err_sys("listen call failed"); } return sockfd; }
TCP是一种流协议 它没有明显边界 两个包的发送可能是下面多种情况
解决办法是
1 每次读取固定字节
函数如下
- int readn(SOCKET fd, char* bp, size_t len) {
- int cnt;
- int rc;
- cnt = len;
- while (cnt > 0) {
- rc = recv(fd, bp, cnt, 0);
- if (rc < 0) {
- return -1;
- }
- if (rc == 0) {
- return len - cnt;
- }
- bp += rc;
- cnt -= rc;
- }
- return len;
- }
2 在报文前面添加首部 说明报文的长度
函数如下
- int readvrec(SOCKET fd, char* bp, size_t len) {
- uint32_t reclen;
- int rc;
- rc = readn(fd, (char *)&reclen, sizeof(uint32_t));
- if (rc != sizeof(uint32_t))
- return rc < 0 ? -1 : 0;
- reclen = ntohl(reclen);
- //如果发送内容大于BUF长度 收取发送内容后丢弃
- if (reclen > len) {
- while (reclen > 0) {
- rc = readn(fd, bp, len);
- if (rc != len)
- return rc < 0 ? -1 : 0;
- reclen -= len;
- if (reclen < len)
- len = reclen;
- }
- return -2;
- }
- //正常情况
- rc = readn(fd, bp, reclen);
- if (rc != reclen)
- return rc < 0 ? -1 : 0;
- return rc;
- }
全部代码如下
通用头文件
- #ifndef __UNP_H__
- #define __UNP_H__
- #include <WinSock2.h>
- #include <iostream>
- #include <WS2tcpip.h>
- #pragma comment(lib,"WS2_32.lib")
- #define MAXLINE 1024
- void err_sys(const char* msg) {
- std::cout << msg << std::endl;
- exit(-1);
- }
- class InitWinSock{
- public:
- InitWinSock(){
- WORD myVersionRequest;
- WSADATA wsaData;
- myVersionRequest = MAKEWORD(2,2);
- int err = WSAStartup(myVersionRequest,&wsaData);
- if(err){
- exit(-1);
- }
- }
- ~InitWinSock(){
- WSACleanup();
- }
- };
- #endif //#ifndef __UNP_H__
客户端
- #include "../common/unp.h"
- #define DEFAULT_IP_ADDR "127.0.0.1"
- InitWinSock initsock;
- struct {
- uint32_t reclen;
- char buf[128];
- }packet;
- int main()
- {
- int sockfd;
- int n;
- struct sockaddr_in servaddr;
- if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- err_sys("sock error");
- }
- memset(&servaddr, 0, sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_port = htons(7500);
- if (inet_pton(AF_INET, DEFAULT_IP_ADDR, &servaddr.sin_addr) <= 0)
- err_sys("inet_pton error");
- /*printf("inet_pton: 0x%x\n", servaddr.sin_addr);*/
- if (connect(sockfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0)
- err_sys("connect error");
- while (fgets(packet.buf, sizeof(packet.buf), stdin) != NULL){
- n = strlen(packet.buf);
- packet.reclen = htonl(n);
- if (send(sockfd, (char*)&packet, n + sizeof(packet.reclen), 0) < 0) {
- err_sys("send fail\n");
- }
- }
- return 0;
- }
服务端
- #include "../common/unp.h"
- InitWinSock initsock;
- int readn(SOCKET fd, char* bp, size_t len) {
- int cnt;
- int rc;
- cnt = len;
- while (cnt > 0) {
- rc = recv(fd, bp, cnt, 0);
- if (rc < 0) {
- return -1;
- }
- if (rc == 0) {
- return len - cnt;
- }
- bp += rc;
- cnt -= rc;
- }
- return len;
- }
- int readvrec(SOCKET fd, char* bp, size_t len) {
- uint32_t reclen;
- int rc;
- rc = readn(fd, (char *)&reclen, sizeof(uint32_t));
- if (rc != sizeof(uint32_t))
- return rc < 0 ? -1 : 0;
- reclen = ntohl(reclen);
- //如果发送内容大于BUF长度 收取发送内容后丢弃
- if (reclen > len) {
- while (reclen > 0) {
- rc = readn(fd, bp, len);
- if (rc != len)
- return rc < 0 ? -1 : 0;
- reclen -= len;
- if (reclen < len)
- len = reclen;
- }
- return -2;
- }
- //正常情况
- rc = readn(fd, bp, reclen);
- if (rc != reclen)
- return rc < 0 ? -1 : 0;
- return rc;
- }
- int main()
- {
- struct sockaddr_in local;
- int s;
- int s1;
- int rc;
- char buf[10];
- struct sockaddr_in peer;
- int peerlen = sizeof(peer);
- local.sin_family = AF_INET;
- local.sin_port = htons(7500);
- local.sin_addr.s_addr = htonl(INADDR_ANY);
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0) {
- err_sys("socket call failed");
- }
- rc = bind(s, (struct sockaddr*)&local, sizeof(local));
- if (rc < 0) {
- err_sys("bind call failure");
- }
- rc = listen(s, 5);
- if (rc) {
- err_sys("listen call failed");
- }
- s1 = accept(s,(struct sockaddr*)&peer,&peerlen);
- if (s1 < 0) {
- err_sys("accept error");
- }
- for (;;) {
- int n = readvrec(s1, buf, sizeof(buf));
- if (n < 0) {
- if(n == -2)
- printf("readvrec buf to short \n");
- else {
- err_sys("readvrec error\n");
- }
- }
- else if (n == 0) {
- err_sys("client disconnected \n");
- }
- else {
- if (n > 9)
- n = 9;
- buf[n] = '\0';
- printf("%s",buf);
- }
- }
- return 0;
- }
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力


【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
2016-02-23 boost::asio 学习草稿