有关UDP超时重传
近来的项目是linux下的网络传输,使用的是UDP,在网上开了很多的资料,都有些问题,而且,最让我郁闷的就是搜索的资料基本上都是那个以“众所周知”开头的有关UDP的超时重传的资料,各种郁闷。
不知道有没有人和我一样遇到很多问题,却找不到答案。
在这里,我就把我的代码分享给大家:我就不说那么多大白话了,那些基础知识大家上网搜一堆一堆的,我就不说了,直接上代码。
操作系统:ubuntu 12.04
select相关。
编译完成后:./server ./client <ip(本机的话就本机的IP或者是127.0.0.1)> 大家估计都知道,写下让和我一样一开始不会的人看。
代码自己分析,相信大家有这个能力,就那么几个函数。
存在一个问题,当然这个问题不影响,大家可以开2个或这个两个以上的客户端同时想服务器发送请求,或者是将数据包内容增加。
这个演示用的数据包很小,所以一般不会出现丢包问题,大家可以各种尝试。
对了,我的循环条件是while(1),所以,到时候要终止程序的,大家自己改进,那么简单的一个问题。
客户端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
#define PORT 4500
#define MAXDATASIZE 1024
struct _DESTINATION_IP
{
char _destinationIp[16];
}DestinationIp;
int main(int argc, char *argv[])
{
int sockfd, numbytes;
int retries = 0;
int retry_max = 3;
char recvbuf[MAXDATASIZE];
char sendbuf[MAXDATASIZE];
fd_set readfds;
socklen_t len;
struct timeval authtime;
struct sockaddr_in server;
len = sizeof(struct sockaddr_in);
if (argc != 2)
{
printf("Usage: %s <IP Address> \n",argv[0]);
exit(1);
}
strcpy(DestinationIp._destinationIp, argv[1]);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("socket() error\n");
exit(1);
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
if (inet_aton(DestinationIp._destinationIp, &server.sin_addr) == 0)
{
perror("inet_aton");
exit(EXIT_FAILURE);
}
while (1)
{
authtime.tv_usec = 0;
authtime.tv_sec = 5;
printf("input message:");
fgets(sendbuf, 40, stdin);
sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&server, len);
FD_ZERO(&readfds); /*清空readfds结构中的fd*/
FD_SET(sockfd, &readfds);/*将sockfd加入到readfds中*/
if (select(sockfd + 1, &readfds, NULL, NULL, &authtime) < 0)
return -1;
/*FD_ISSET来检测fd在fdset集合中的状态是否发生变化,返回整形,发生变化为真非0*/
if (FD_ISSET(sockfd, &readfds) != 0)
{
if ((numbytes = recvfrom(sockfd, recvbuf, MAXDATASIZE, 0, (struct sockaddr *)&server, &len)) == -1) // recvfrom返回收到的字节数,失败返回0.
{
printf("recvfrom() error\n");
exit(1);
}
recvbuf[numbytes]='\0';
printf("Receive Message: %s \n", recvbuf);
continue;
}
if (++retries >= retry_max)
{
printf("请检查网络设置是否正确,然后重启本软件。\n");
return -1;
}
}
close(sockfd);
}
服务器:#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 4500
#define MAXDATASIZE 1024
int main(void)
{
int sockfd, num;
struct sockaddr_in server, client;
socklen_t sin_size = sizeof(struct sockaddr_in);
char recvmsg[MAXDATASIZE];
char sendmsg[MAXDATASIZE];
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("Creating socket failed.");
exit(1);
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
{
perror("Bind error.");
exit(1);
}
while (1)
{
num = recvfrom(sockfd, recvmsg, MAXDATASIZE, 0, (struct sockaddr *)&client, &sin_size);
if (num < 0)
{
perror("recvfrom error\n");
exit(1);
}
recvmsg[num] = '\0';
printf("You got a message (%s) from %s:%d\n", recvmsg, inet_ntoa(client.sin_addr), htons(client.sin_port) );
printf("input message:");
fgets(sendmsg, 40, stdin);
sendto(sockfd, sendmsg, strlen(sendmsg), 0, (struct sockaddr *)&client, sin_size);
}
close(sockfd);
}