WindowsAPI 查阅笔记:网络通信

客户端:

记得在编译的时候加上这个 -lwsock32 -lws2_32
不然会报错 undefined reference to `__imp_WSAStartup‘

注意:如果端口在此之前被占了,则不会发生预期的结果

服务端,得到连接后创建线程,执行处理函数。

client.cpp

//client.cpp
#include <cstdio>
#include <winsock2.h>
#include <iostream>
#include <cstring>
#include <windows.h>

//#pragma comment(lib, "ws2_32.lib") 

#define RECV_BUFFER_SIZE 8192

int main(int argc, char **argv)
{
	//变量定义
	SOCKADDR_IN clientService;	//地址
	SOCKET	ConnectSocket;		//Socket
	WSADATA	wsaData;			//库
//	LPVOID recvbuf;				//接收缓存
	char *recvbuf ;
//	char recvbuf[64];
	int bytesSent;
	int bytesRecv = 0;
	
	//默认的发送数据 
//	char sendbuf[32] = "get information"; 
	char sendbuf[32] = "download file";
	
	//初始化 Socket 库,保证 ws2_32.dll 已经加载
	int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if(iResult != NO_ERROR){
		printf("Error at WSAStartup()\n");
	} 
	//创建 Socket
	ConnectSocket = socket(AF_INET,	//Ipv4
		SOCK_STREAM,	//顺序的、可靠的、基于链接的、双向数据流通信
		IPPROTO_TCP		//使用 TCP 协议 
	);
	if(ConnectSocket == INVALID_SOCKET)
	{
		printf("Error at socket(): %ld\n",
			WSAGetLastError());
		WSACleanup();
		return 3;
	}
	//设置服务端的通信协议、ip地址、端口
	clientService.sin_family = AF_INET;
	clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
	clientService.sin_port = htons(12321);
	//连接到服务端
	if(	connect(
		ConnectSocket,				//socket
		(SOCKADDR*) &clientService,	//地址
		sizeof(clientService)		//地址的大小
		) == SOCKET_ERROR 
	){
		printf("Failed to connect(%d)\n",WSAGetLastError());
		WSACleanup();
		return 2;
	}else{
		printf("连上了~!\n"); 
	}
	
	//准备发送数据
	// 如果输入的参数是 "-d" ,那么发生的数据事 "download file"
	// 否则发送的数据是 "get information"
	if(argc == 2 && (!lstrcmp(argv[1],"-d"))){
		lstrcpyn(sendbuf, "download file", 32);
	} 
	
	//向服务端发送数据
	bytesSent = send(ConnectSocket,	//socket
		sendbuf,					//发送的数据
		lstrlen(sendbuf)+1,			//数据长度
		0);							//无标志
	if(bytesSent == SOCKET_ERROR){
		printf("send error(%d)\n",
			WSAGetLastError());
		closesocket(ConnectSocket);
		return 1;
	} 
	printf("Bytes Sent: %ld\n",bytesSent);
	//准备接收数据
//	recvbuf = HeapAlloc(GetProcessHeap(), 0, RECV_BUFFER_SIZE);
	recvbuf = (char*)malloc(sizeof(char)*RECV_BUFFER_SIZE);
	//循环接收
	while(bytesRecv != SOCKET_ERROR)
	{
		
		bytesRecv = recv(ConnectSocket,	//socket
			recvbuf,					//接收数据缓存
			RECV_BUFFER_SIZE,			//缓存大小
			0);							//无标志
		if(bytesRecv == 0){
			printf("Connection Closed.\n");
			break;
		} 
		//TODO,处理接收到的数据,这里只简单地将收到的数据大小显示
		printf("Bytes Recv: %ld\n", bytesRecv); 
		printf("data:%s\n",recvbuf);
	} 
//	HeapFree(GetProcessHeap(), 0, recvbuf);
	free(recvbuf);
	WSACleanup();
	
	return 0;
} 

server.cpp

//  server.cpp 

#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <cstring>
#include <cstdio>

//常量
#define DEFAULT_PORT "12321"	//端口
#define MAX_REQUEST 1024		//接收数据的缓存大小
#define BUF_SIZE	4096		//发送数据的缓存大小

/***************************
用于接收和发送数据的线程
	为每一个连接的客户端创建一个接收发送数据的线程,
	可以使用多个客户端同时连接到服务端 
**************************/ 

DWORD WINAPI CommunicationThread(LPVOID lpParameter)
{
	DWORD dwTid = GetCurrentThreadId();
	//获得参数 socket
	SOCKET socket = (SOCKET)lpParameter;
	//为接收数据分配空间
//	LPSTR szRequest = HeapAlloc(GetProcessHeap(), 0, MAX_REQUEST); 
	char *szRequest = (char *)malloc(sizeof(char)*MAX_REQUEST);
	int iResult;
	//用于保存send 的返回值,既实际发送的数据的大小 
	int bytesSent;	
	
	//接收数据
	iResult = recv(socket,	//socket
		szRequest,			//接收缓存
		MAX_REQUEST,		//缓存大小
		0);					//标志
	if(iResult == 0){	//接收数据失败,连接已关闭
		printf("COnnection closing...\n");
//		HeapFree(GetProcessHeap(), 0, szRequest);
		free(szRequest);
		closesocket(socket);
		return 1;
	}else if(iResult == SOCKET_ERROR){//接收数据失败,Socket 错误
		printf("recv failed: %d\n",WSAGetLastError());
//		HeapFree(GetProcessHeap(), 0, szRequest);
		free(szRequest);
		closesocket(socket);
		return 1;
	}else if(iResult > 0){	//接收数据成功 
		//显示接收到的数据
		printf("\tCommunicationThread(%d)\tBytes received: %d\n",dwTid, iResult);
		printf("\tCommunicationThread(%d)\trequest string is (%s)\n",dwTid, szRequest);
		
		//如果接收到的数据是 "download file"
		if(lstrcmpi(szRequest, "download file") == 0){
			//读取文件 download.txt 将发送
			HANDLE hFile;
//			LPVOID lpReadBuf;	//发生缓存
			char *lpReadBuf;
			
			DWORD dwBytesRead;
			DWORD dwFileSize;
			DWORD dwSendFile = 0;
			hFile = CreateFile("download.txt",
				GENERIC_READ,
				FILE_SHARE_READ,
				NULL,
				OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL,
				NULL);
				
			if(hFile == INVALID_HANDLE_VALUE){
				printf("\tCommunicationThread\tCould not open file (error %d)\n",
					GetLastError());
				send(socket, "error", 6, 0);
				closesocket(socket);
				return 1;
			} 
			//分配发送数据的缓存
//			lpReadBuf = HeapAlloc(GetProcessHeap(), 0, BUF_SIZE);
			lpReadBuf = (char*) malloc(sizeof(char) * BUF_SIZE);
			//获取文件的大小
			dwFileSize = GetFileSize(hFile, NULL);
			//循环发送
			while(1){
				//读文件到缓存
				if(!ReadFile(hFile, lpReadBuf, BUF_SIZE, &dwBytesRead, NULL)){
					printf("\tCommunicationThread\tCould not read from file (error %d)\n",
						GetLastError());
					closesocket(socket);
					CloseHandle(hFile);
					return 1;
				} 

				//发送读取的文件数据
				bytesSent = send(socket, lpReadBuf, dwBytesRead, 0);
				if(bytesSent == SOCKET_ERROR){
					printf("\tCommunicationThread\tsend error %d\n",WSAGetLastError());
					closesocket(socket);
					CloseHandle(hFile);
					return 1; 
				} 
				//显示发送数据的大小
				printf("\tCommunicationThread(%d)\tsend %d bytes\n", dwTid, bytesSent);
				//累加,已经发送的大小
				dwSendFile += dwBytesRead;
				//如果所以文件数据都已经发送
				if(dwSendFile == dwFileSize){
					printf("\tCommunicationThread\tFile download ok\n");
					break;
				} 
			}
			//释放内存、关闭连接、关闭文件
	//		HeapFree(GetProcessHeap(), 0, lpReadBuf);
			free(lpReadBuf);
			CloseHandle(hFile);
			closesocket(socket); 
		}
		//如果接收到的数据 是 "get information"
		
		else if(lstrcmpi(szRequest, "get information") == 0){
			//发送数据 
			bytesSent = send(socket,	//socket
				"this is information",	//数据
				lstrlen("this is information")+1,//数据长度
				0);	//标志
			//判断是否成功
			if(bytesSent == SOCKET_ERROR){
				printf("\tCommunicationThread\tsend error %d\n",
					WSAGetLastError());
				closesocket(socket);
				return 1;
			} 
			printf("\tCommunicationThread(%d)\tsend %d bytes\n",dwTid, bytesSent);
		} else{
			//收到未知数据
			printf("unreferenced request\n"); 
		}
	}
		//释放接收数据缓存 ,关闭Socket
	//	HeapFree(GetProcessHeap(), 0, szRequest);
	free(szRequest);

	closesocket(socket);
	return 0;
}

/***************************
socket 服务端主程序 
************************/

int __cdecl main(void)
{
	WSADATA wsaData;
	//监听 Socket 
	SOCKET ListenSocket = INVALID_SOCKET;	 
	//连接 Socket
	SOCKET ClientSocket = INVALID_SOCKET;
	
	struct addrinfo *result = NULL, hints;
	int iResult;		//保存返回的结果
	
	
	//初始化 WinSock,保证 Ws2_32.dll 已经加载
	iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if(iResult != 0){
		printf("WSAStartup failed: %d\n",iResult);
		return 1;
	}
	
	//地址
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = AI_PASSIVE;
	
	//获取主机地址,保证网络协议可用等
	iResult = getaddrinfo(NULL,	//本机
		DEFAULT_PORT,		//端口
		&hints,				//使用的网络协议、连接类型等
		&result);			//结果
	if(iResult != 0){
		printf("getaddrinfo failed: %d\n",iResult);
		WSACleanup();
		return 1;
	} 
	//创建 Socket,用于监听
	ListenSocket = socket(
		result->ai_family,	//网络协议,AF_INET,Ipv4
		result->ai_socktype,	//类型,SOCK_STREAM
		result->ai_protocol	//通讯协议,TCP 
	);
	if(ListenSocket == INVALID_SOCKET){
		printf("socket failed: %ld\n",
			WSAGetLastError());
		freeaddrinfo(result);
		WSACleanup();
		return 1;
	} 
	
	//绑定到端口
	iResult = bind(ListenSocket,
		result->ai_addr,
		(int)result->ai_addrlen)
	;
	if(iResult == SOCKET_ERROR){
		printf("bind failed: %d\n",WSAGetLastError());
		freeaddrinfo(result);
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	} 
	printf("bind\n");
	
	freeaddrinfo(result);	//reuslt 不再使用
	
	//开始监听
	iResult = listen(ListenSocket, SOMAXCONN);
	printf("start listen......\n");
	if(iResult == SOCKET_ERROR)
	{
		printf("listen failed: %d\n",WSAGetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	} 
	while(1){
		//接收客户端连接,accept函数会等待,直到连接建立
		printf("ready to accept\n");
		ClientSocket = accept(ListenSocket, NULL, NULL);
		//accept 函数返回,说明已经有客户端连接
		//返回连接 Socket
		printf("accept a connetion\n");
		if(ClientSocket == INVALID_SOCKET){
			printf("accept failed: %d\n",WSAGetLastError());
			closesocket(ListenSocket);
			break;//等待连接错误,退出循环 
		} 
		//为每一个连接创建一个数据发送的接收线程
		//使服务端又可以立即接收到其他客户端的连接
		if(!CreateThread(
			NULL,
			0,
			CommunicationThread,	//线程函数
			(LPVOID)ClientSocket,	//将Socket 作为传入参数
			0,
			NULL))
		{
			printf("Create Thread error (%d)",
				GetLastError());
			break; 
		} 
	}
	//循环退出,释放DLL
	WSACleanup();  
	return 0;
}

download.txt

Hello,This is download.txt
你好,这里是 download.txt 文件
hello, 这里是 download.txt file. 

运行结果

先运行 server 再运行 client。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值