《TCP/IP网络编程》阅读笔记--基于TCP的服务器端/客户端

目录

1--TCP/IP协议栈

2--TCP服务器端默认函数调用顺序

3--TCP客户端的默认函数调用顺序

4--Linux实现迭代回声服务器端/客户端

5--Windows实现迭代回声服务器端/客户端

6--TCP原理

7--Windows实现计算器服务器端/客户端


1--TCP/IP协议栈

        TCP/IP协议栈共分 4 层,可以理解为数据收发分成了 4 个层次化过程;

链路层:

        链路层是物理链接领域标准化的结果,专门定义LAN、WAN、MAN等网络标准;

IP层:

        IP层用于解决数据传输过程中路径的选择问题;

TCP/IP层:

        即传输层,用于解决数据传输的问题(数据顺序、可靠性等);

应用层:

        程序员根据数据传输规则,编写规定的程序(例如Socket)来实现数据传输;

2--TCP服务器端默认函数调用顺序

        一般 TCP 服务器端调用默认函数的顺序如下:socket() 创建 Socket → bind() 分配Socket 地址 → listen() 等待连接请求状态 → accept() 允许连接 → read()/write() 数据交换 → close() 断开连接;

        调用 listen() 函数进入等待连接请求状态,只有服务器端调用了 listen() 函数,客户端才能进入可发出连接请求的状态;

#include <sys/socket.h>int listen(int sock, int backlog); // 成功时返回 0, 失败时返回 -1;// sock 表示希望进入等待连接请求状态的Socket的文件描述符
// backlog 表示连接请求等待队列的长度,即最多可以使多少个连接请求进入队列

        服务器端调用 accept() 函数来受理客户端的连接请求,即受理等待队列中待处理的客户端连接请求;

#include <sys/socket.h>int accept(int sock, struct sockaddr* addr, socklen_t* addrlen);
// 成功时返回创建的Socket的文件描述符,失败时返回-1

3--TCP客户端的默认函数调用顺序

        一般 TCP 客户端调用默认函数的顺序如下:socket() 创建 Socket → connect() 请求连接 → read()/write() 交换数据 → close() 断开连接;

        在服务器端调用 listen() 函数创建连接请求等待队列后,客户端可通过调用 connect() 函数来请求连接;

#include <sys/socket.h>int connect(int sock, struct sockaddr* servaddr, socklen_t addrlen);// sock 表示客户端socket的文件描述符
// servaddr 保存了目标服务器端地址信息
// addrlen 第二个结构体参数 servaddr 的地址变量长度,以字节为单位

4--Linux实现迭代回声服务器端/客户端

服务器端:

// gcc echo_server.c -o echo_server
// ./echo_server 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 1024
void error_handling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[]){int serv_sock, clnt_sock;char message[BUF_SIZE];int str_len, i;struct sockaddr_in serv_adr, clnt_adr;socklen_t clnt_adr_sz;if(argc != 2){printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock = socket(PF_INET, SOCK_STREAM, 0);if(serv_sock == -1){error_handling("socket() error");}memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);serv_adr.sin_port = htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1){error_handling("bind() error");}if(listen(serv_sock, 5) == -1){error_handling("listen() error");}clnt_adr_sz = sizeof(clnt_adr);for(i = 0; i < 5; i++){clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);if(clnt_sock == -1){error_handling("accept() error");}else{printf("Connected client %d \n", i+1);}while((str_len = read(clnt_sock, message, BUF_SIZE)) != 0){write(clnt_sock, message, str_len);}close(clnt_sock);}close(serv_sock);return 0;
}

客户端:

// gcc echo_client.c -o echo_client
// ./echo_client 127.0.0.1 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 1024void error_handling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[]){int sock;char message[BUF_SIZE];int str_len;struct sockaddr_in serv_adr;if(argc != 3){printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}sock = socket(PF_INET, SOCK_STREAM, 0);if(sock == -1){error_handling("socket() error");}memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = inet_addr(argv[1]);serv_adr.sin_port = htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1){error_handling("connect() error!");}else{puts("Connected.......");}while(1){fputs("Input message(Q to quit): ", stdout);fgets(message, BUF_SIZE, stdin);if(!strcmp(message, "q\n") || !strcmp(message, "Q\n")){break;}write(sock, message, strlen(message));str_len = read(sock, message, BUF_SIZE-1);message[str_len] = 0;printf("Message from server: %s", message);}close(sock);return 0;
}   

运行结果:

5--Windows实现迭代回声服务器端/客户端

服务器端:

// gcc echo_server_win.c -o echo_server_win -lwsock32
// echo_server_win 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>#define BUF_SIZE 1024void ErrorHandling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[]){WSADATA wsaData;SOCKET hServSock, hClntSock;char message[BUF_SIZE];int strLen, i;SOCKADDR_IN servAdr, clntAdr;int clntAdrSize;if(argc != 2){printf("Usage : %s <port>\n", argv[0]);exit(1);}if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ErrorHandling("WSAStartup() error!");}hServSock = socket(PF_INET, SOCK_STREAM, 0);if(hServSock == INVALID_SOCKET){ErrorHandling("socket() error");}memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = htonl(INADDR_ANY);servAdr.sin_port = htons(atoi(argv[1]));if(bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR){ErrorHandling("bind() error");}if(listen(hServSock, 5) == SOCKET_ERROR){ErrorHandling("listen() error");}clntAdrSize = sizeof(clntAdr);for(int i = 0; i < 5; i++){hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &clntAdrSize);if(hClntSock == -1){ErrorHandling("accept() error");}else{printf("Connected client %d \n", i + 1);}while((strLen = recv(hClntSock, message, BUF_SIZE, 0)) != 0){send(hClntSock, message, strLen, 0);}closesocket(hClntSock);}closesocket(hServSock);WSACleanup();return 0;
}

客户端:

// gcc echo_client_win.c -o echo_client_win -lwsock32
// echo_client_win 127.0.0.1 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>#define BUF_SIZE 1024void ErrorHandling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char *argv[]){WSADATA wsaData;SOCKET hSocket;char message[BUF_SIZE];int strLen;SOCKADDR_IN servAdr;if(argc != 3){printf("Usage: %s <IP> <port>\n", argv[0]);exit(1);}if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ErrorHandling("WSAStartup() error!");}hSocket = socket(PF_INET, SOCK_STREAM, 0);if(hSocket == INVALID_SOCKET){ErrorHandling("socket() error");}memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = inet_addr(argv[1]);servAdr.sin_port = htons(atoi(argv[2]));if(connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR){ErrorHandling("connect() error!");}else{puts("Connected........");}while(1){fputs("Input message(Q to quit): ", stdout);fgets(message, BUF_SIZE, stdin);if(!strcmp(message, "q\n") || !strcmp(message, "Q\n")){break;}send(hSocket, message, strlen(message), 0);strLen = recv(hSocket, message, BUF_SIZE - 1, 0);message[strLen] = 0;printf("Message from server: %s", message);}closesocket(hSocket);WSACleanup();return 0;
}

测试结果:

6--TCP原理

I/O缓冲:

        当调用 write() 函数后并不会立即传输数据,而是将数据移至输出缓冲;

        同样当调用 read() 函数后也并不会马上接收数据,而是将数据移至输入缓冲;

        TCP会控制数据流,使用滑动窗口协议(参考博主之前的笔记:TCP流量控制)来限制数据传输不会超过输入缓冲的大小;

TCP 协议使用三次握手来建立连接,使用四次挥手来断开连接;(具体分析参考书中图解)

7--Windows实现计算器服务器端/客户端

服务器端:

// gcc op_server_win.c -o op_server_win -lwsock32
// op_server_win 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>#define BUF_SIZE 1024
#define OPSZ 4void ErrorHandling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}int calculate(int opnum, int opnds[], char op){int result = opnds[0], i;switch(op){case '+':for(i = 1; i < opnum; i++) result += opnds[i];break;case '-':for(i = 1; i < opnum; i++) result -= opnds[i];break;case '*':for(i = 1; i < opnum; i++) result *= opnds[i];break;}return result;
}int main(int argc, char* argv[]){WSADATA wsaData;SOCKET hServSock, hClntSock;char opinfo[BUF_SIZE];int result, opndCnt, i;int recvCnt, recvLen;SOCKADDR_IN servAdr, clntAdr;int clntAdrSize;if(argc != 2){printf("Usage: %s <port>\n", argv[0]);exit(1);}if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ErrorHandling("WSAStartup() error!");}hServSock = socket(PF_INET, SOCK_STREAM, 0);if(hServSock == INVALID_SOCKET){ErrorHandling("socket() error!");}memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = htonl(INADDR_ANY);servAdr.sin_port = htons(atoi(argv[1]));if(bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR){ErrorHandling("bind() error");}if(listen(hServSock, 5) == SOCKET_ERROR){ErrorHandling("listen() error");}clntAdrSize = sizeof(clntAdr);for(int i = 0; i < 5; i++){opndCnt = 0;hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &clntAdrSize);recv(hClntSock, (char*)&opndCnt, 1, 0); // recv one byterecvLen = 0;while((opndCnt * OPSZ + 1) > recvLen){recvCnt = recv(hClntSock, &opinfo[recvLen], BUF_SIZE - 1, 0);recvLen += recvCnt;}result = calculate(opndCnt, (int*)opinfo, opinfo[recvLen - 1]);send(hClntSock, (char*)&result, sizeof(result), 0);closesocket(hClntSock);}closesocket(hServSock);WSACleanup();return 0;
}

客户端:

// gcc op_client_win.c -o op_client_win -lwsock32
// op_client_win 127.0.0.1 9190#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>#define BUF_SIZE 1024
#define RLT_SIZE 4
#define OPSZ 4void ErrorHandling(char *message){fputs(message, stderr);fputc('\n', stderr);exit(1);
}int main(int argc, char* argv[]){WSADATA wsaData;SOCKET hSocket;char opmsg[BUF_SIZE];int result, opndCnt, i;SOCKADDR_IN servAdr;if(argc != 3){printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ErrorHandling("WSAStartup() error!");}hSocket = socket(PF_INET, SOCK_STREAM, 0);if(hSocket == INVALID_SOCKET){ErrorHandling("socket() error!");}memset(&servAdr, 0, sizeof(servAdr));servAdr.sin_family = AF_INET;servAdr.sin_addr.s_addr = inet_addr(argv[1]);servAdr.sin_port = htons(atoi(argv[2]));if(connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR){ErrorHandling("connect() error!");}else{puts("Connected........");}fputs("Operand count: ", stdout);scanf("%d", &opndCnt);opmsg[0] = (char)opndCnt; // one bytefor(i = 0; i < opndCnt; i++){printf("Operand %d: ", i + 1);scanf("%d", (int*)&opmsg[i*OPSZ + 1]);}fgetc(stdin);fputs("Operator: ", stdout);scanf("%c", &opmsg[opndCnt * OPSZ + 1]); // one bytesend(hSocket, opmsg, opndCnt * OPSZ + 2, 0);recv(hSocket, (char*)&result, RLT_SIZE, 0);printf("Operation result: %d \n", result);closesocket(hSocket);WSACleanup();return 0;
}

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/103940.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CUDA说明和安装[window]

文章目录 1、查看版本信息查看GPU查看cuda版本其他方法 2区分 了解cudaCUDA ToolkitNVCCcuDNN 3/ 安装过程4/版本的问题CUDA Toolkit和 显卡驱动 的版本对应CUDA / CUDA Toolkit和cuDNN的版本对应 5/关于CUDA和Cudnn**5.1 CUDA的命名规则****5.2 如何查看自己所安装的CUDA的版本…

对可再生能源和微电网集成研究的新控制技术和保护算法进行基线和测试及静态、时域和频率分析研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

RabbitMQ 知识点解读

1、AMQP 协议 1.1、AMQP 生产者的流转过程 当客户端与Broker 建立连接的时候&#xff0c;会调用factory .newConnection 方法&#xff0c;这个方法会进一步封装成Protocol Header 0-9-1 的报文头发送给Broker &#xff0c;以此通知Broker 本次交互采用的是AMQPO-9-1 协议&…

华为认证系统学习大纲及课程

前言 任何学习过程都需要一个科学合理的学习路线&#xff0c;才能够有条不紊的完成我们的学习目标。华为认证网络工程师所需学习的内容纷繁复杂&#xff0c;难度较大&#xff0c;所以今天特别为大家整理了一个全面的华为认证网络工程师学习大纲及课程&#xff0c;帮大家理清思…

【动手学深度学习】--文本预处理

文章目录 文本预处理1.读取数据集2.词元化3.词表4.整合所有功能 文本预处理 学习视频&#xff1a;文本预处理【动手学深度学习v2】 官方笔记&#xff1a;文本预处理 对于序列数据处理问题&#xff0c;在【序列模型】中评估了所需的统计工具和预测时面临的挑战&#xff0c;这…

机器学习入门教学——过拟合、欠拟合、模型验证、样本拆分

1、过拟合 定义 过拟合指的是模型对训练数据拟合的太好&#xff0c;以至于无法很好地泛化到新数据。原因 训练数据不足模型太复杂&#xff08;如深层神经网络&#xff09;训练时间太长后果 模型在训练数据上表现良好&#xff0c;但在测试数据上表现较差。解决方法 增加训练数据…

HJ48 从单向链表中删除指定值的节点

Powered by:NEFU AB-IN Link 文章目录 HJ48 从单向链表中删除指定值的节点题意思路代码 HJ48 从单向链表中删除指定值的节点 题意 输入一个单向链表和一个节点的值&#xff0c;从单向链表中删除等于该值的节点&#xff0c;删除后如果链表中无节点则返回空指针。 思路 单向链表…

OpenRoads地形模型添加(增补)地形点

创建三维点&#xff0c;将创建的点对象添加到现有地形模型。 在ORD建模工作流&#xff1a; 地形、分析、点、分析点&#xff0c;在需要添加点的位置读出地模的高程&#xff08;图1&#xff09;&#xff1b; 图1 几何、平面、点添加高程点&#xff0c;特征设为地形随机点、高…

解决本地jar包导入maven

1、确定是否安装maven 2、输入导入命令 命令说明 <path-to-file>为你jar包所在的路径&#xff08;尽量简单并且不要含中文&#xff09; <group-id>为grouId号&#xff0c;与<artifact-id>组成唯一识别你jar包的坐标&#xff0c;当不在公共资源jar包中&#…

Visual Stadio使用技巧

C语言调试技巧 Debug 和 Release 的介绍 Debug&#xff1a;通常称为调试版本&#xff0c;它包含调试信息&#xff0c;并且不作任何优化&#xff0c;便于程序员调试&#xff08;可调试&#xff09;。 Release&#xff1a;通常称为发布版本&#xff0c;它往往时进行了各种优化&a…

app源代码安全检测的重要性

源代码审计 app软件代码漏洞扫描&#xff08;源代码安全检测&#xff09;是从安全的角度对代码进行安全测试和评估。同时结合丰富的安全知识、编程经验和测试技术&#xff0c;采用静态分析和人工审查的方法&#xff0c;发现代码架构和编码中的安全漏洞&#xff0c;在代码之前将…

ArcGIS美化科研论文地图(利用在线底图)

1.加载在线底图服务 在ArcGIS Desktop中打开Catalog窗口&#xff0c;在GIS Servers中点击Add ArcGIS Server&#xff0c;之后选项全部默认&#xff0c;仅在URL中输入以下网址https://services.arcgisonline.com/arcgis 之后就可以看到底图了 我们在WorldElevation3D中选择Nat…