win32网络编程(学习笔记):简单的TCP 客户端、TCP服务端

本文深入介绍了TCP网络编程的基础知识,包括网络架构、协议、IP地址和端口的概念。接着,详细阐述了TCP协议的使用,讲解了CS(Client-Server)架构与BS(Browser-Server)架构的区别,并展示了Windows上实现TCP服务器和客户端的典型步骤。通过实例代码,演示了TCP服务器的创建、监听和通信过程,以及TCP客户端的连接和数据发送。
摘要由CSDN通过智能技术生成

目录

0x01 网络编程的基础复习

0x02 TCP协议的使用

0x03 TCP服务器

0x04 TCP 客户端


0x01 网络编程的基础复习

1.协议:大家都遵守的规则

2.网络架构:

五层网络架构:

  1. 应用层:应用程序
  2. 传输层:四层交换机 光猫
  3. 网络层:   三层交换机 路由器
  4. 数据链路层:网桥(淘汰)二层交换机
  5. 物理层: 中继器 集线器

七层网络架构:将应用层拆分成了三层,应用层=应用层+表示层+会话层,为了便于开发者编程时去区分。

  1. 应用层
    1. 功能:文件传输 email ftp文件服务器,虚拟终端
    2. 协议:ftp tftp http (smtp pop3) telnet
  2. 表示层
    1. 功能:数据格式化,代码转换,数据加密
    2. 协议:
  3. 会话层
    1. 功能:建立或解除与其他连接的关系
    2. 协议:
  4. 传输层
    1. 功能:建立端对端的接口
    2. 协议:TCP UDP
  5. 网络层
    1. 功能:为数据选择路由
    2. 协议:IP
  6. 数据链路层
    1. 功能:传输有地址的数据 错误检测
    2. 协议:SLIP CSLIP ppp ppp3
  7. 物理层
    1. 功能:用来传输电信号,光信号
    2. 协议:   ISO2110 IEEE802(无线电协议)

3.ip地址:本质是一个大小为32位的无符号整数,我们平常用点分十进制的字符串表示

4.端口:就是套接字的编号,一共有65536个端口 0到65535 即用16bit存储该编号

一般我们开发程序使用1W以上的端口比较安全
 

0x02 TCP协议的使用

cs 架构:client  server架构,app、木马 本质上都是cs架构

bs 架构:browser  server 架构 ,web应用 是bs架构,必须要借助于浏览器,并且离不开http协议

windows上的CS架构的编程套路:

服务器 Server客户端 Client
1.获取协议版本:WSAStartup1.获取协议版本
2.创建套接字:socket2.创建套接字
3.创建协议地址族:SOCKADDR_IN3.获取服务器的协议地址族
4.绑定:bind 
5.监听:listen 
6.接受客户端连接:accept (三次握手建立连接)4.连接服务器 conn
7.通信:fwrite、send、recv、sendto、recvfrom

5.通信

8关闭套接字::closeSocket (四次挥手断开连接)6关闭套接字
9.清理协议信息:WSACleanup7.清理协议信息

注意:TCP建立的数据传输通道是全双工的。

数据传输通道:

单工:单向收发,例如电视机,收音机

半双工:双向收发,但同一时刻只能收或者发,例如对讲机

全双工:双向同时收发 ,例如 电话

0x03 TCP服务器

// Server.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <windows.h>

int main()
{
	//1.获取版本信息
	WSADATA wsaData;
	//参数1:协议版本号 WORD 类型 
	//参数2:存储版本信息的结构体的地址
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//MAKEWORD是一个宏函数,传入两个字节类型的数据,整合成一个WORD类型的数据
	//MAKEWORD(2,2) 就是产生一个高字节为2,低字节为2的16位的数据
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		printf("得到的版本号不正确,请求版本失败\n");
		return -1;
	}	
	else {
		printf("请求版本成功\n");
	}
	//2 创建tcp socket
	SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (SOCKET_ERROR == serverSocket) { //如果返回值为-1
		printf("创建tcp套接字失败:%d\n",GetLastError());
		return -1;
	}
	printf("创建socket成功\n");
	//3 创建协议地址族 (配置控制信息)
	SOCKADDR_IN serverAddr = { 0 };
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.107"); //将点分十进制转化32位unsigned int
	serverAddr.sin_port = htons(10001); //因为我们的主机是小端系统,路由器交换机是大端系统,所以我们发给大端系统的端口号应该小端转大端
	//4 绑定
	int r = bind(serverSocket,(sockaddr*) &serverAddr, sizeof serverAddr);
	if (-1 == r) {
		printf("绑定失败!\n");
		closesocket(serverSocket);
		WSACleanup();
		return -1;
	}
	printf("绑定成功!\n");
	//5 监听
	r = listen(serverSocket, 10);
	if (-1 == r) {
		printf("监听失败!\n");
		closesocket(serverSocket);
		WSACleanup();
		return -1;
	}
	printf("监听成功!\n");
	//6 接收客户端连接
	SOCKADDR_IN clientAddr = { 0 }; //用于接收客户端的协议地址族(就是控制信息)
	int len = sizeof clientAddr; //用于接收客户端协议地址族信息的大小
	SOCKET connClient = accept(serverSocket, (sockaddr*)&clientAddr, &len);
	//SOCKET connClient = accept(serverSocket, NULL, NULL); //如果不想存储客户端的协议地址族信息,可以传NULL地址
	if (SOCKET_ERROR == connClient) {
		printf("接收客户端连接失败!\n");
		closesocket(serverSocket);
		WSACleanup();
		return -1;
	}
	//inet_ntoa() 将32位unisigned int 转化为点分十进制的string
	printf("有客户端连接到服务器了:%s:%d!\n",inet_ntoa(clientAddr.sin_addr),clientAddr.sin_port);
	//7 通信
	char buff[1024];
	while (1) {
		r = recv(connClient, buff, 1023, NULL);//最多接收1023,最后一位留给结束符号
		//最后一个参数为flag 标志接收方式,NULL表示阻塞方式
		//返回值是接收到数据的长度
		if (r > 0) {
			buff[r] = 0; //让buff的最后一个字符为\0,因为字符串以\0为结束标志
			printf("%s::%s\n", inet_ntoa(clientAddr.sin_addr), buff);
		}
	}
	//8 关闭socket
	closesocket(serverSocket);
	//9 清除协议版本
	WSACleanup();
	while (1);
	return 0;
}


0x04 TCP 客户端

// Client.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <windows.h>


int main()
{
	//1.获取版本信息
	WSADATA wsaData;
	//参数1:协议版本号 WORD 类型 
	//参数2:存储版本信息的结构体的地址
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//MAKEWORD是一个宏函数,传入两个字节类型的数据,整合成一个WORD类型的数据
	//MAKEWORD(2,2) 就是产生一个高字节为2,低字节为2的16位的数据
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		printf("得到的版本号不正确,请求版本失败\n");
		return -1;
	}
	else {
		printf("请求版本成功\n");
	}
	//2 创建tcp socket
	SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (SOCKET_ERROR == clientSocket) { //如果返回值为-1
		printf("创建tcp套接字失败:%d\n", GetLastError());
		return -1;
	}
	printf("创建socket成功\n");
	//3 配置服务器协议地址族 (配置控制信息)
	SOCKADDR_IN serverAddr = { 0 };
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.107"); //将点分十进制转化32位unsigned int
	serverAddr.sin_port = htons(10001); //因为我们的主机是小端系统,路由器交换机是大端系统,所以我们发给大端系统的端口号应该小端转大端
	//4 连接服务器
	int r;
	r = connect(clientSocket, (sockaddr*)&serverAddr, sizeof serverAddr);
	if (SOCKET_ERROR == r) {
		printf("连接服务器失败\n");
		return -1;
	}
	printf("连接服务器成功!\n");

	//5 通信

	char buff[1024];
	while (1) {
		memset(buff, 0, 1024);
		printf("请输入要发送的数据:");
		scanf("%s", buff);
		r = send(clientSocket, buff, strlen(buff),NULL);
		if (r > 0) {
			printf("发送%d字节数据成功!\n", r);
		}
		else {
			printf("发送失败!\n");
		}
	}
	//6 关闭socket
	closesocket(clientSocket);
	//7 清除协议版本
	WSACleanup();
	while (1);
	return 0;

}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值