Win32 Socket的使用

Win32 Socket的使用

在微信公众号上看到了一篇文章,其中的内容是有关FTP传输文件的,文章的地址找不到了,但是是大佬写的文章。公众号:涛哥依旧。

下面来记录一下学习过程:

讲到Socket就不得不提网络通信模型,就是客户端–服务器模型。服务器等待客户端来连接。最初学习网络通信是在《VC++详解 第三本》这本书里面,有兴趣的大家可以都可以看看。

其中分别讲述了客户端–服务器模式的流程:

一、基于TCP(面向连接)服务器端Socket编程

1.基于TCP(面向连接)服务器端Socket编程的流程:

(1)创建一个套接字(socket).

(2)将套接字绑定到一个本地地址和端口上(bind).

(3)将套接字设为监听模式,准备接受客户端的请求(listen)

(4)等待客户请求的到来(accept).当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字。

(5)用返回的套接字和客户端进行通信(send/recv).

(6)返回或者等待另一客户请求。

(7)关闭套接字。

2.基于TCP(面向连接)客户端Socket编程的流程:

(1)创建一个套接字(socket).

(2)向服务器端发送连接请求(connect).

(3)和服务器进行通信(send/recv)

(4) 关闭套接字。

二、基于UDP(面向无连接)服务器端Socket编程:

3.基于UDP(面向无连接)服务器端Socket编程的流程:

(1)创建一个套接字(socket).

(2)将套接字绑定到一个本地地址和端口上(bind).

(3)准备接受数据(recvfrom)

(4)关闭套接字

4.基于UDP(面向无连接)客户端Socket编程的流程:

(1)创建一个套接字(socket).

(2)向服务器发送数据(sendto).

(3)关闭套接字。

下面我们以TCP的方式来构建一个实例程序:

TCP服务端程序:

#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#include "Ws2tcpip.h"
#include <string>
#include <fstream>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

int main()
{
	// tcp连接部分
	WORD wVersionRequested;      // 用来指定准备要加载到套接字库的版本
	WSADATA wsaData;             // 库版本的有关信息
	wVersionRequested = MAKEWORD(1,1);
	// WSAStartup():①加载套接字库②进行套接字版本的协商,确定要使用的套接字的版本
	WSAStartup(wVersionRequested, &wsaData);  // 加载套接字库
	// socket:创建套接字
	// AF_INET:指定地址族;SOCK_STREAM:指定Socket的类型为流式套接字;Protocol:指定与地址族相关的协议
	unsigned int  sockSrv = socket(AF_INET,SOCK_STREAM,0);  // 创建套接字
	SOCKADDR_IN  addrSrv;  // 指定了该套接字本地地址信息

	// 表示地址族,对于IP地址,将一直是AF_INET 
	addrSrv.sin_family = AF_INET;  
	// 套接字的主机IP地址
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 
	// htons:将u_short值从主机字节顺序转化为TCP/IP网络字节顺序 // 指定要分配给套接字的端口号
	addrSrv.sin_port = htons(8888);  
	// 将Socket与本地的IP地址和端口号绑定
	bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));  

	// listen():将指定的套接字设置为监听模式
	// backlog:等待连接队列的最大长度
	listen(sockSrv,5);  

	SOCKADDR_IN addrClient;
	int len = sizeof(SOCKADDR);
	// accept():接受客户端发送的连接请求
	// sockSrv:当前监听的Socket; addrClient:连接的客户端的IP地址和端口号
	unsigned int SockConn = accept(sockSrv, (SOCKADDR*)&addrClient,&len);  

	// 接收ftp client发送的文件的文件长度
	char sizeFileStr[20] = {0};
	// 从一个已连接的套接字中接收数据
	recv(SockConn, sizeFileStr, sizeof(sizeFileStr)-1,0);   
	int fileSize = atoi(sizeFileStr);

	// 接收ftp client发送的文件的并保存
	char recvBuf[1024] = {0};
	int recvTotalSize = 0;

	char* buffer;
	char absolutePath[MAX_PATH];
	memset(absolutePath, 0, MAX_PATH);
	GetModuleFileNameA(NULL, absolutePath, MAX_PATH);
	string strPath = (std::string)absolutePath;
	int nPos = strPath.find_last_of('\\', strPath.length());
	string strDirectory = strPath.substr(0, nPos);  // 返回不带有可执行文件名的路径
	char* pFileName = "\\2.txt";
	buffer = const_cast<char*>(strDirectory.c_str());
	strcat(buffer, pFileName);
	std::fstream fs;
	fs.open(buffer, std::ios::in);
	if (!fs)
	{
		ofstream fout(buffer);
		if (fout)
		{
			fout << "写入内容,也可以不写入" << endl;
			fout.close();
		}
	}
	else
	{
		std::cout << "该文件已经存在!" << endl;
	}

	FILE* fp = fopen(buffer, "wt");
	while (recvTotalSize<fileSize)
	{
		int recvSize = recv(SockConn,recvBuf,sizeof(recvBuf),0);
		recvTotalSize += recvSize;
		printf("recved %d MB\n", recvTotalSize/(1024*1024));
		fwrite(recvBuf,1,recvSize,fp);
	}
	fclose(fp);

	if (recvTotalSize == fileSize)
	{
		printf("Done!");
	}
	else
	{
		printf("Error!");
	}

	closesocket(sockSrv);   // 关闭已建立连接的套接字
	WSACleanup();           // 终止对套接字到使用
	getchar();
    return 0;
}

TCP客户端程序:

#include "stdafx.h"
#include<stdio.h>
#include<direct.h> // _getcwd
#include<iostream>
#include<winsock2.h>
#include "Ws2tcpip.h"
#include <fstream>
#include<windows.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;

int main()
{
	//tcp连接部分
	WORD wVersionRequested;
	WSADATA wsaData;
	wVersionRequested = MAKEWORD(1,1);
	WSAStartup(wVersionRequested, &wsaData);
	SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0);
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(8888);
	int nRtn = connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
	if (nRtn == SOCKET_ERROR)
	{
		cout << "连接服务器失败!请重试" << endl;
		return -1;
	}
	
	// 在指定的目录下读取创建文件
	char* buffer;
	char absolutePath[MAX_PATH];
	memset(absolutePath, 0, MAX_PATH);
	GetModuleFileNameA(NULL, absolutePath, MAX_PATH);
	string strPath = (std::string)absolutePath;
	int nPos = strPath.find_last_of('\\', strPath.length());
	string strDirectory = strPath.substr(0, nPos);  // 返回不带有可执行文件名的路径
	char* pFileName = "\\1.txt";
	buffer = const_cast<char*>(strDirectory.c_str());
	strcat(buffer, pFileName);
	std::fstream fs;
	fs.open(buffer, std::ios::in);
	if (!fs)
	{
		ofstream fout(buffer);
		if (fout)
		{
			for (int i = 0; i < 100000; i++)
			{
				fout << "写入内容,也可以不写入" << endl;
			}
			fout.close();
		}
	}
	else
	{
		cout << "该文件已经存在!" << endl;
	}
	//Ftp Client读取文件的长度
	FILE* fp=fopen(buffer,"rt");
	fseek(fp,0,SEEK_END);
	int totalSize = ftell(fp);
	fclose(fp);

	//ftp Client发送文件长度
	char fileSizeChr[20] = {0};
	_itoa(totalSize, fileSizeChr,10);
	send(sockClient, fileSizeChr,strlen(fileSizeChr)+1,0);

	//ftp client发送文件
	fp = fopen(buffer,"rt");
	int readSize = 0;
	int sendTotalSize = 0;
	char sendBuf[1024] = { 0 };
	while ((readSize=fread(sendBuf,1,sizeof(sendBuf),fp))>0)
	{
		send(sockClient, sendBuf, readSize, 0);
		sendTotalSize += readSize;
		printf("Send %d MB\n", sendTotalSize/(1024*1024));
	}
	fclose(fp);
	if (sendTotalSize == totalSize)
	{
		printf("Done!");
	}
	else
	{
		printf("Error!");
	}
	
	closesocket(sockClient);
	WSACleanup();
	getchar();
    return 0;
}

程序说明:主要利用本地回环地址测试,在打开客户端程序时新建一个txt文本: 1.txt,并且在其中写入内容。然后等连接上服务器,将1.txt的内容发送给服务器端,然后服务器端生成一个新的txt,2.txt用来接收收到的数据。具体运行结果如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3qV45O3l-1691826441169)(C:\Users\Administrator\Desktop\微信截图_20230812154138.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q36SB5Ay-1691826441171)(C:\Users\Administrator\Desktop\微信截图_20230812154202.png)]

小结:

代码中用到的各个函数如下:

socket:创建套接字

bind:将套接字绑定到本地端口上

listen:将指定的套接字设置为监听模式

accept:允许在套接字上尝试传入连接。

在这个示例中还有几个结构体和其他的函数介绍,大家可以去微软的官方网站去查看具体的作用。Win32

本次示例的源码如下,需要的朋友可以去下载:源码

好了,这次就介绍到这里了,欢迎大家一起学习交流。

icrosoft.com/zh-cn/windows/win32/api/winsock2/nf-winsock2-accept):允许在套接字上尝试传入连接。

在这个示例中还有几个结构体和其他的函数介绍,大家可以去微软的官方网站去查看具体的作用。Win32

本次示例的源码如下,需要的朋友可以去下载:源码

好了,这次就介绍到这里了,欢迎大家一起学习交流。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值