⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sender.cpp

📁 Visual C++模拟计算机网络中停止等待协议发送接收数据的过程
💻 CPP
字号:
// sender.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <WinSock2.h>
#include <string.h>
#include "../header/ARQ.h"
#include "../header/Exception.h"

// 服务器端口
#define SERVER_PORT 2280
//	最大重传次数
#define MAXRETRY 8
//	传送传时时间
#define TIMEOUT 3000

#pragma comment(lib,"ws2_32.lib")//设置link时的lib库

using namespace std;

SOCKET PrimaryUDP;
char ServerIP[20];
char FilePath[MAX_PATH];

// 用作奇偶检校的序号
bool g_number = false;
//	返回的控制字符
char g_bcc;

HANDLE m_hEvent;


void InitWinSock()
{
	WSADATA wsaData;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		throw Exception("Windows sockets 2.2 startup unsuccessful");
	}
	else{
		printf("Using %s (Status: %s)\n",
			wsaData.szDescription, wsaData.szSystemStatus);
		printf("with API versions %d.%d to %d.%d\n\n",
			LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
			LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
	}
}

void mksock(int type)
{
	PrimaryUDP = socket(AF_INET, type, 0);
	if (PrimaryUDP < 0)
	{
		throw Exception("create socket error");
	}
}

void BindSock()
{
	sockaddr_in sin;
	sin.sin_addr.S_un.S_addr = INADDR_ANY;
	sin.sin_family = AF_INET;
	sin.sin_port = 0;

	if (bind(PrimaryUDP, (struct sockaddr*)&sin, sizeof(sin)) < 0)
		throw Exception("bind error");
}

bool ASendto()
{
	sockaddr_in remote;
	remote.sin_addr.S_un.S_addr = inet_addr(ServerIP);
	remote.sin_family = AF_INET;
	remote.sin_port = htons(SERVER_PORT);
	int fromlen = sizeof(remote);

	//	打开文件
	FILE * file;
	if((file = fopen(FilePath, "rb")) == NULL)
	{
		cout<<FilePath<<" open error"<<endl;
		return false;
	}
	cout<<"file open succeed"<<endl;

	// 设置文件指针位置
	SetFilePointer(file, 0, NULL, FILE_BEGIN);

	BSC bsc;
	bsc.header = STX;bsc.tail = ETX;

	//	设为有信号
	SetEvent(m_hEvent);

	//	分段序号
	bool number = false;	

	unsigned long dwRead = -1;
	bool sendComplete = false;
	while(!sendComplete)
	{	
		//	清空数据
		memset(bsc.data, 0, MAXBSCLENGTH);
		//	当前分块的奇偶序号
		bsc.number=number;
		//	记录当前的分块序号
		g_number = bsc.number;

		if (dwRead ==-1)//第一次应发送文件请求消息
		{
			//	发送文件请求
			bsc.bcc = ENQ;			
			char * filename = FilePath;
			if ((filename = strrchr(FilePath,'\\'))==NULL)
				filename = FilePath;
			else
				++filename;
			strcpy(bsc.data,filename);
			dwRead = 0;
		}
		else
		{
			if(!feof(file))
			{
				bsc.bcc = SYN;
				int i = fread(bsc.data, sizeof(char),MAXBSCLENGTH , file);
				cout<<"read:"<<i<<"\tsend:"<<sizeof(bsc.data)<<endl;
				dwRead+=i;
			}
			else
			{
				//	发送完毕
				bsc.bcc = EOT;
				sendComplete = true;
				cout<<"send complete.send size:"<<dwRead<<endl;
				fclose(file);
			}
			
		}
				
		for(int i=0;i<MAXRETRY;i++)
		{
			sendto(PrimaryUDP,(char*)&bsc,sizeof(bsc),0,(sockaddr*)&remote,fromlen);
			ResetEvent(m_hEvent);
			DWORD reslut =  WaitForSingleObject(m_hEvent,TIMEOUT);
			if (reslut == WAIT_OBJECT_0)
			{
				//	收到应答消息,一种是ACK,一种是NAK
				if (g_bcc == NAK)
				{			
					if (i == MAXRETRY -1)
					{
						return false;
					}
					//	继续重传
					continue;
				}
				else
				{
					//	收到应答消息
					//cout<<"send succeed"<<endl;
					break;
				}
			}
			else if(i == MAXRETRY-1)
			{
				cout<<"send file failed"<<endl;
				return false;
			}
		}

		//	开始发下一段数据
		number = !number;
	}

	return true;
}

DWORD WINAPI ARecv(LPVOID lpParam)
{
	sockaddr_in remote;
	int sinlen = sizeof(remote);
	BSC buffer;
	int iread = 0;
	while (true)
	{
		iread = recvfrom(PrimaryUDP,(char*)&buffer,sizeof(buffer),0,(sockaddr*)&remote,&sinlen);
		//	处理ACK与NAK
		if (iread == SOCKET_ERROR)
		{
			continue;
		}
		//	与当前的分块序号进行比较,看是不是当前块的应答
		if (buffer.number!=g_number)
		{
			continue;
		}
		if (buffer.bcc == ACK || buffer.bcc == NAK)
		{
			//	保存返回的控制字符
			g_bcc = buffer.bcc;
			SetEvent(m_hEvent);
		}
		

	}
	return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
	InitWinSock();			
	mksock(SOCK_DGRAM);
	BindSock();

	cout<<"Please input receiver ip:";
	cin>>ServerIP;

	cout<<"Please input the file path:";
	cin>>FilePath;

	m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	CreateThread(NULL, 0, ARecv, NULL, 0, NULL);  

	if (!ASendto())
	{
		cout<<"file send failed"<<endl;
		getchar();
	}

	getchar();
	getchar();
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -