停止-等待协议:(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实现
————考研狗的日常笔记欢迎各位神仙前来斧正