mirror of
https://github.com/skywind3000/kcp.git
synced 2025-03-14 17:42:56 +08:00
183 lines
4.0 KiB
C
183 lines
4.0 KiB
C
#include <stdio.h>
|
||
#include <unistd.h>
|
||
#include <sys/socket.h>
|
||
#include <arpa/inet.h>
|
||
#include <sys/ioctl.h>
|
||
|
||
#include "test.h"
|
||
#include "ikcp.c"
|
||
|
||
typedef struct
|
||
{
|
||
int socket;
|
||
struct sockaddr_in server_sa;
|
||
int channel;
|
||
} test_ctx_t;
|
||
|
||
|
||
int
|
||
kcp_output(const char *buf, int len, ikcpcb *kcp, void *user)
|
||
{
|
||
test_ctx_t *ctx = (test_ctx_t *)user;
|
||
|
||
sendto(ctx->socket, buf, len, 0, (struct sockaddr *)&ctx->server_sa,
|
||
sizeof(ctx->server_sa));
|
||
|
||
return 0;
|
||
}
|
||
|
||
int
|
||
main(int argc, char **argv)
|
||
{
|
||
test_ctx_t ctx;
|
||
char *server_addr = "127.0.0.1";
|
||
int server_port = 50000;
|
||
int channel;
|
||
|
||
switch (argc)
|
||
{
|
||
case 4:
|
||
server_port = atoi(argv[3]);
|
||
if (server_port <= 0 || 65535 < server_port)
|
||
{
|
||
printf("invalid port: %s\n", argv[3]);
|
||
return 1;
|
||
}
|
||
case 3: server_addr = argv[2];
|
||
case 2:
|
||
channel = atoi(argv[1]);
|
||
if (channel <= 0)
|
||
{
|
||
printf("invalid channel number: %s\n", argv[1]);
|
||
return 1;
|
||
}
|
||
break;
|
||
default:
|
||
printf("Usage: %s <channel> [server_ip] [server_port]\n", argv[0]);
|
||
return 1;
|
||
}
|
||
|
||
// init ctx
|
||
bzero(&ctx, sizeof(ctx));
|
||
|
||
ctx.channel = channel;
|
||
|
||
ctx.server_sa.sin_family = AF_INET;
|
||
ctx.server_sa.sin_port = htons(server_port);
|
||
if (inet_pton(AF_INET, server_addr, &ctx.server_sa.sin_addr) < 0)
|
||
{
|
||
printf("invalid server address: %s\n", server_addr);
|
||
return 1;
|
||
}
|
||
|
||
// create udp
|
||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||
if (s == -1) return 1;
|
||
|
||
int nb;
|
||
nb = 1;
|
||
ioctl(s, FIONBIO, &nb);
|
||
|
||
ctx.socket = s;
|
||
|
||
ikcpcb *kcp;
|
||
|
||
kcp = ikcp_create(ctx.channel, &ctx);
|
||
if (kcp == NULL) return 1;
|
||
|
||
ikcp_setoutput(kcp, kcp_output);
|
||
ikcp_nodelay(kcp, 1, 1, 2, 1);
|
||
ikcp_wndsize(kcp, 1024, 1024);
|
||
|
||
IUINT32 current = iclock();
|
||
IUINT32 slap = current + 20;
|
||
IUINT32 index = 0;
|
||
IUINT32 next = 0;
|
||
ssize_t n;
|
||
char buffer[65536];
|
||
IINT64 sumrtt = 0;
|
||
int count = 0;
|
||
int maxrtt = 0;
|
||
IUINT32 ts1 = iclock();
|
||
|
||
printf("inited\n");
|
||
|
||
while (1)
|
||
{
|
||
isleep(1);
|
||
current = iclock();
|
||
ikcp_update(kcp, iclock());
|
||
|
||
// 每隔 20ms,kcp1发送数据
|
||
for (; current >= slap; slap += 20)
|
||
{
|
||
((IUINT32 *)buffer)[0] = index++;
|
||
((IUINT32 *)buffer)[1] = current;
|
||
|
||
// 发送上层协议包
|
||
ikcp_send(kcp, buffer, 8);
|
||
}
|
||
|
||
// 处理底层数据
|
||
while (1)
|
||
{
|
||
n = recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL);
|
||
if (n < 0) break;
|
||
|
||
ikcp_input(kcp, buffer, n);
|
||
}
|
||
|
||
// kcp收到应用据
|
||
while (1)
|
||
{
|
||
n = ikcp_recv(kcp, buffer, sizeof(buffer));
|
||
|
||
// 没有收到包就退出
|
||
if (n < 0) break;
|
||
|
||
char *p = buffer;
|
||
char *last = p + n;
|
||
while (p + 8 <= last)
|
||
{
|
||
IUINT32 sn = *(IUINT32 *)(p + 0);
|
||
IUINT32 ts = *(IUINT32 *)(p + 4);
|
||
IUINT32 rtt = current - ts;
|
||
|
||
if (sn != next)
|
||
{
|
||
// 如果收到的包不连续
|
||
printf("ERROR sn %d<->%d\n", (int)count, (int)next);
|
||
return 1;
|
||
}
|
||
|
||
p += 8;
|
||
next++;
|
||
sumrtt += rtt;
|
||
count++;
|
||
if (rtt > (IUINT32)maxrtt) maxrtt = rtt;
|
||
|
||
printf("[RECV] sn=%d rtt=%d\n", (int)sn, (int)rtt);
|
||
|
||
if (next > 1000) goto done;
|
||
}
|
||
|
||
if (p != last)
|
||
{
|
||
// 收到不完整的包
|
||
printf("receiving a incomplete package\n");
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
done:
|
||
|
||
ts1 = iclock() - ts1;
|
||
|
||
ikcp_release(kcp);
|
||
|
||
printf("result (%dms):\n", (int)ts1);
|
||
printf("avgrtt=%d maxrtt=%d\n", (int)(sumrtt / count), (int)maxrtt);
|
||
|
||
return 0;
|
||
} |