基于UDP协议模拟停止等待协议

停止-等待协议:(stop-and-wait)是最简单但也是最基础的数据链路层协议。
所谓停止等待就是发送方发送一个数据帧便停止发送,等待接收方发送一个确认帧后继续发送下一个帧以此来实现无差错传输。

停止等待协议用于通信系统中,两个相连的设备相互发送信息时使用,以确保信息不因丢包或包乱序而丢失,是最简单的自动重传请求方法。

当发送方发送一个数据帧的同时会立即启动一个计时器,当在计时器到期还没有收到接收方的确认帧,就默认该帧丢失在链路中了,则重新发送。如果接收方收到重复的帧,则丢弃该帧,并重复回复该帧的确认帧给发送方。

code

接收方

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <wait.h>
#include <arpa/inet.h>

#define port 35789
#define IP "127.0.0.1"

char buf[BUFSIZ];
char sbuf[BUFSIZ];
char filename[257];
struct sockaddr_in saddr, caddr;
int len ,len1;
int sfd;
int flag0, flag1;

int main(){
	sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sfd == -1){
		perror("Create socket error: ");
		exit(0);
	}
	bzero(&saddr, sizeof(saddr));
	bzero(&caddr, sizeof(caddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(port);
	saddr.sin_addr.s_addr = inet_addr(IP);
	len1 = sizeof(saddr);
	len = sizeof(caddr);
	if((bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr))) == -1){
		perror("bind error: ");
		exit(0);
	}
	char r[5];
	memset(r, 0, sizeof(r));
	int tmp = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len);
	if(tmp == -1){
		perror("recv error:");
	}
	else{
		char str[256];
		printf("recv from %s at port %d\n", inet_ntop(AF_INET, &caddr.sin_addr, str, sizeof(str)), ntohs(caddr.sin_port));
	}
	printf("%s\n", buf);
	r[0] = buf[0];
	printf("r:%s\n", r);
	sendto(sfd, r, strlen(r), 0, (struct sockaddr *)&caddr, len);
	int i;
	for(i = 1; i < strlen(buf); ++i){
		filename[i - 1] = buf[i];
	}
	strcat(filename, ".recv");
	int fd = open(filename, O_RDWR | O_CREAT, 0755);
	if(fd < 0){
		perror("open error: "); 
		exit(1);
	}
	close(fd);
	fd = open(filename, O_RDWR | O_APPEND);
	if(fd < 0){
		perror("open error: "); 
		exit(1);
	}
	flag0 = buf[0];
	memset(buf, 0, sizeof(buf));
	int n;
	while(n = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &len)){
		printf("recv: %s\n", buf);
		if(buf[0] == flag0){
			sendto(sfd, buf, strlen(buf), 0, (struct sockaddr *)&caddr, len1);
		}
		else{
			write(fd, buf + 1, n - 1);
			flag0 = buf[0];
		}
		if(n <= 0){
			break;
		}
	}
	close(fd);
	return 0;
}

发送方

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <netdb.h>
#include <wait.h>
#include <arpa/inet.h>

#define port 35789
#define IP "127.0.0.1"

char buf[BUFSIZ];
char sbuf[BUFSIZ + 5];
int fd = 0;
int sfd = 0;
struct sockaddr_in saddr, caddr;
int len, len1;

void handler(){
	printf("rsend\n");
	sendto(sfd, sbuf, strlen(sbuf), 0, (struct sockaddr *)&saddr, sizeof(saddr));
	printf("send: %s\n", sbuf);
	alarm(1);
}

int main(){
	signal(SIGALRM, handler);
	char fileName[256];
	printf("Please input send file name!\n");
	memset(fileName, 0, sizeof(fileName));
	scanf("%s", fileName);
	sfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sfd < 0){
		perror("Create socket error:");
		exit(1);
	}
	int set = 1;
	bzero(&saddr, sizeof(saddr));
	bzero(&caddr, sizeof(caddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(port);
	saddr.sin_addr.s_addr = inet_addr(IP);
	len = sizeof(saddr);
	/*
	if(bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1){
		perror("Bind error:");
		exit(1);
	}
	*/
	fd = open(fileName, O_RDONLY);
	if(fd < 0){
		perror("open error:");
		exit(1);
	}
	else{
		printf("Sending......\n");
	}
	int cnt = 0;
	ssize_t n;
	char rbuf[256];
	memset(sbuf, 0, sizeof(buf));
	sbuf[0] = ((cnt++) % 2) + '0';
	strcat(sbuf, fileName);
	printf("%s\n", sbuf);
	alarm(1);
	while(1){
		sendto(sfd, sbuf, strlen(sbuf), 0, (struct sockaddr *)&saddr, sizeof(saddr));
		printf("send: %s\n", sbuf);
		int tt = recvfrom(sfd, rbuf, 256, 0, (struct sockaddr *)&saddr, &len);
		printf("recv: %s\n", rbuf);
		//rbuf[tt] = 0;
		printf("rbuf: %c\n", rbuf[0]);
		printf("sbuf]: %c\n", sbuf[0]);
		if(rbuf[0] == sbuf[0]){
			printf("==\n");
			alarm(0);
			break;
		}
	}
	while((n = read(fd, buf, BUFSIZ))){
		memset(sbuf, 0, sizeof(sbuf));
		memset(rbuf, 0, sizeof(rbuf));
		sbuf[0] = ((cnt++) % 2) + '0';
		strcat(sbuf, buf);
		alarm(1);
		while(1){
			sendto(sfd, sbuf, strlen(sbuf), 0, (struct sockaddr *)&caddr, sizeof(caddr));
			printf("%s\n", sbuf);
			recvfrom(sfd, rbuf, 256, 0, (struct sockaddr *)&caddr, &len1);
			printf("recv: %s\n", rbuf);
			rbuf[len1] = '\0';
			if(rbuf[0] == sbuf[0]){
				alarm(0);
				break;
			}
		}
	}
	return 0;
}


以上代码基于Ubuntu18.04实现
————考研狗的日常笔记欢迎各位神仙前来斧正

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值