#include <iostream>
#include <tchar.h>
#include <winsock2.h>
#include <windows.h>
#include <string.h>
#ifndef __ARQ_H__
#define __ARQ_H__
//停止等待协议BSC控制字符
#define STX (char)2 // 文始
#define ETX (char)3 // 文终
#define ENQ (char)5 // 询问
#define SYN (char)16 // 同步
#define EOT (char)4 // 送毕
#define ACK (char)6 // 正应答
#define NAK (char)15// 负应答
//BSC数据报文格式
#define MAXBSCLENGTH 1000
typedef struct Datagram
{
bool number; //0或者1
char data[MAXBSCLENGTH];//正文
char bcc; //控制字符
} BSC;
#endif
// 服务器端口
#define SERVER_PORT 2280
#define MAXRETRY 8 //最大重传次数
#define TIMEOUT 3000//传送传时时间
#pragma comment(lib,"ws2_32.lib")//设置link时的lib库
using namespace std;
SOCKET PrimaryUDP;
bool g_number = false; // 序号
char g_bcc; //返回的控制字符
char*ServerIP="127.0.0.1";
char*FilePath="C:\\source.txt";
char*FileSavePath="C:\\destination.txt";
sockaddr_in remote;
HANDLE m_hEvent;
void InitWinSock() // 初始化套接字
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
cout<<"Windows sockets 2.2 startup unsuccessful";
}
else{
cout << " OK ,initWinSock succeed !" << endl;
}
}
void mksock(int type)
{
PrimaryUDP = socket(AF_INET, type,0);
if (PrimaryUDP < 0)
{
cout << "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)
cout<< "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;
//设为有信号
SetEvent(m_hEvent);// sets the state of the specified event object to signaled
bool number = false;
long dwRead = 0;
bool sendComplete = false;
while(!sendComplete)
{
// 清空数据
memset(bsc.data,0,MAXBSCLENGTH);
// 当前分块的奇偶序号
bsc.number=number;
// 记录当前的分块序号
g_number = bsc.number;
if(!feof(file))
{
bsc.bcc = SYN;
int i = fread(bsc.data, sizeof(char),MAXBSCLENGTH , file);
cout<<"read:"<<i<<"\tsend:"<<sizeof(bsc.data)<<endl;
cout<<"帧号"<< g_number<< "当前发送窗口" << 1 << 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
{
//收到应答消息
break;
}
}
else if(i == MAXRETRY-1)
{
cout<<"send file failed"<<endl;
return false;
}
cout <<"帧号"<<g_number<<"发送超时了"<< endl;
cout <<"帧号"<<g_number<<"send again"<< endl;
}
number = !number; // 开始发下一段数据
}
return true;
}
DWORD WINAPI ARecv(LPVOID lpParam)
{
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 main(int argc, _TCHAR* argv[])
{
InitWinSock();
mksock(SOCK_DGRAM);
BindSock();
m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
CreateThread(NULL, 0, ARecv, NULL, 0, NULL);
if (!ASendto()){
cout<<"file send failed"<<endl;
}
system("pause");
return 0;
}
/*
// receiver.cpp : 定义控制台应用程序的入口点。
// 服务器端口
#define SERVER_PORT 2280
#pragma comment(lib,"ws2_32.lib")//设置link时的lib库
using namespace std;
//SOCKET PrimaryUDP;
char FileSavePath[MAX_PATH];
void rInitWinSock()//初始化套接字
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
cout<<"Windows sockets 2.2 startup unsuccessful";
}
else{
cout<<"initwinsock error"<< endl;
}
}
void rmksock(int type)
{
PrimaryUDP = socket(AF_INET, type,0);
if (PrimaryUDP < 0)
{
cout<<"create socket error";
}
}
void rBindSock()
{
sockaddr_in sin;
sin.sin_addr.S_un.S_addr = INADDR_ANY;
sin.sin_family = AF_INET;
sin.sin_port = htons(SERVER_PORT);
if (bind(PrimaryUDP, (struct sockaddr*)&sin, sizeof(sin)) < 0)
cout<<"bind error";
}
DWORD WINAPI rARecv(LPVOID lpParam)
{
FILE * file = NULL;
sockaddr_in remote;
int sinlen = sizeof(remote);
BSC buffer,bsc;
bsc.header = STX;bsc.tail = ETX;
memset(bsc.data, 0, MAXBSCLENGTH);
int iread = 0;
unsigned long dwReceived = 0;
bool number = true;//发送方的数据开始发送时的序号设为0,为了判断是不是第一次一段数据,所以这里标为1
while (true)
{
iread= recvfrom(PrimaryUDP,(char*)&buffer,sizeof(buffer),0,(sockaddr*)&remote,&sinlen);
if (SOCKET_ERROR == iread || buffer.header != STX || buffer.tail != ETX)
{
// 数据错误,发送负应答
cout<<"received a error data"<<endl;
bsc.bcc = NAK;bsc.number=false;//number这时没有实际的意义
sendto(PrimaryUDP,(char*)&bsc,sizeof(bsc),0,(sockaddr*)&remote,sinlen);
continue;
}
if (buffer.number == number)
{
// 重复收到数据,发送应答消息
cout<<"received a repeat data"<<endl;
bsc.bcc = ACK;
bsc.number = buffer.number;
sendto(PrimaryUDP,(char*)&bsc,sizeof(bsc),0,(sockaddr*)&remote,sinlen);
continue;
}
switch(buffer.bcc)
{
case ENQ:
{
number = !number;//准备接收下一段数据
// 文件请求
cout<<"received a file request message,filename:"<<buffer.data<<endl;
// 打开文件
if(strcmp((FileSavePath+strlen(FileSavePath)-1),"\\")!=0)
strcat(FileSavePath,"\\");
strcat(FileSavePath,buffer.data);
if((file = fopen(FileSavePath, "ab")) == NULL)
{
cout<<"file open failed"<<endl;
return 1;
}
break;
}
case SYN:
{
number = !number;// 文字发送中
int i =0;
if((i=fwrite(buffer.data, sizeof(char), sizeof(buffer.data), file)) <= 0)
{
cout << "write failed" << endl;
return 1;
}
dwReceived += i;
cout<<"write:"<<i<<"\treceived:"<<sizeof(buffer.data)<<endl;
break;
}
case EOT:
{
number = !number;// 文件发送完毕
cout<<"file received completely,save path:"<<FileSavePath<<",received size:"<<dwReceived<<endl;
fclose(file);
break;
}
default:
{
// 数据错误,发送负应答
bsc.bcc = NAK;bsc.number=false;
sendto(PrimaryUDP,(char*)&bsc,sizeof(bsc),0,(sockaddr*)&remote,sinlen);
continue;
break;
}
}
// 发送应答消息
bsc.bcc = ACK;
bsc.number = buffer.number;
sendto(PrimaryUDP,(char*)&bsc,sizeof(bsc),0,(sockaddr*)&remote,sinlen);
}
return 0;
}
int r_tmain(int argc, _TCHAR* argv[])
{
InitWinSock();
数据链路层停等控制协议socket编程实现
5星 · 超过95%的资源 需积分: 10 155 浏览量
2010-04-06
19:25:57
上传
评论 2
收藏 5KB RAR 举报
xueloveyangjing
- 粉丝: 2
- 资源: 30
最新资源
- zephyr sdk package 2
- zephyr sdk package 1
- optimization.ipynb
- 数据库标识码BSM重排序工具、重构标识码工具
- 基于C语言的校园导航系统报告.doc
- __init__.py
- tensorflow-gpu-2.6.5-cp39-cp39-manylinux2010-x86-64.whl
- tensorflow-rocm-2.13.1.600-cp38-cp38-manylinux2014-x86-64.whl
- tensorflow-rocm-2.13.0.570-cp311-cp311-manylinux2014-x86-64.whl
- 3ds_1.0_3.6.ipa
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
- 1
- 2
- 3
前往页