随笔

static函数不导出符号但是可以取地址,keil编译器竟然是大端存储

static函数不导出符号但是可以取地址

keil编译器竟然是大端存储

keil printf

和标准的ansi c的printf有所不同, ansi中通过下表指定数据的位宽, keil中简陋一些, 只有三个长度修饰符

image_1bl03pjqtfqa17gbgkgqu9m5e9.png-78.5kB

b : 8位

h : 16位

l : 32位

都是放在specifier (d, x, f等等)的前面

keil C51数据类型和存储器类型

总结了 keil C51数据类型和存储器类型

image_1bl03j66u1lv51rila2p1ref6jp9.png-71.3kB

转的别处的, int是16位

存储器类型         说 明

data                  直接访问内部数据存储器(128字节),访问速度最快
对应图中RAM中的的低128字节, 使用直接访问(0x00 – 0x7F)

bdata                可位寻址内部数据存储器(16字节),允许位与字节混合访问
对应图中RAM中的位寻址空间(0x20 – 0x2F)

idata                 间接访问内部数据存储器(256字节),允许访问全部内部地址
对应整个RAM, 但是用间接访问(0x00 – 0xFF)

pdata                分页访问外部数据存储器(256字节),用MOVX @Ri指令访问
对应图中外部存储器(0x0000 – 0x0FFF, C8051F340只有4K外部XRAM)

xdata                外部数据存储器(64KB),用MOVX @DPTR指令访问
对应图中外部存储器(0x0000 – 0x0FFF, C8051F340只有4K外部XRAM)

code                 程序存储器(64KB),用MOVC @A+DPTR指令访问
对应图中FLASH(0x0000 – 0xFBFF

直接寻址是使用指令MOV A,direct
间接寻址是使用指令MOV a,@Ri

对于C8051F34x, 直接寻址与间接寻址速度都为2个时钟周期. 访问外部存储器(MOVC, MOVX)则需要3个时钟周期

image_1bl03j66u1lv51rila2p1ref6jp9.png-71.3kB

Verilog:(1) 上升沿 和 下降沿

Verilog:(1) 上升沿 和 下降沿

数字电路中,把电压的高低用逻辑电平来表示。逻辑电平包括高电平和低电平这两种。不同的元器件形成的数字电路,电压对应的逻辑电平也不同。在TTL门电路中,把大于3.5伏的电压规定为逻辑高电平,用数字1表示;把电压小于0.3伏的电压规定为逻辑低电平,用数字0表示。
数字电平从0变为1 的那一瞬间叫作上升沿在Verilog等语言中,用posedge表述
从1到0的那一瞬间(时刻)叫作下降沿 在Verilog等类似语言中, 用negedge表达
上升沿触发是当信号有上升沿时的开关动作,当电位由低变高而触发输出变化的就叫上升沿触发。也就是当测到的信号电位是从低到高也就是上升时就触发,叫做上升沿触发。
附:
信号上升沿如果不考虑传输过程中出现变化的话,应该取决于信号产生电路。当然如果是输入数字信号处理后输出(运放算一种情况)数字信号的情况下,输入数字信号应该满足此电路要求(上升沿、下降沿、‘1’时电平电压,‘0’时电平电压,电路最高工作频率等),但输入信号处理后的输出数字信号的特点和前级就没有关系了,此时取决于此数字信号处理电路的输出特性了。

udp隧道(STUN)

前两天稍微研究了下通过UDP建隧道穿过NAT路由器, 自己写了个实现, 中间因为考试等事宜耽误了几天, 今天终于能用了.

说起udp隧道, 不得不说下nat. nat现在在市面上再常见不过, 市面上几乎所有的家用路由器, 网吧, 企业, 学校, 手机wifi热点, 无一不使用nat. nat是当前共享上网的主要方式.

不过nat的弊端也是明显的, nat一般只有少数个外网端口, 但却为多数个内网主机提供网络服务. 大家想想, 家里宽带是不是只有一个口接WAN, 其余四个都接LAN. 这就造成了内网主机无法直接与外网主机进行点对点通讯. 首先, 外部主机对内部主机是无知的, 无法对其发出tcp连接, 这还好说, 可以让内部主机主动对外部主机发出连接, 但假如两天主机都在nat内, 就很苦恼了. udp隧道是通过一个在公共互联网的主机作为服务器, 扮演一个中介的角色, 让两台处于nat内部的主机接上线.

首先先要说一下nat的种类, 在stun的标准文档(RFC3489)中定义了两大种nat类型: 1.对称型nat, 2.圆锥形nat, 对于第一种对称性nat, stun是无能为力的. 圆锥形又分三种, 完全圆锥型NAT、受限圆锥型NAT和端口受限圆锥型NAT, 这三种stun都可以穿过.

对称型nat.

如下图所示:

image_1bl02vap6ei5s7s112g1mbk14lc9.png-27.2kB

对称型nat在转发同一主机同一端口号(ip和port都相同)发出的的数据时, 如果对端服务器不是同一个, 则选用不同的端口号进行转发, 这将导致无法进行nat穿越.
如图所示

  • 在客户端: nat内主机192.168.1.100通过同一端口8000分别向5.6.7.8:56214和5.6.7.9:12540发出数据包. 地址对: { 192.168.1.100:8000 – 5.6.7.8:56214 } { 192.168.1.100:8000 – 5.6.7.9:12540 }
  • 在路由器: nat路由器1.2.3.4分别选用了两个不同的端口转发数据包(1.2.3.4:34594和1.2.3.4:34595 ), 地址对: { 1.2.3.4:34594 – 5.6.7.8:56214 } { 1.2.3.4:34595 – 5.6.7.9:12540 }
  • 在服务器端: 两个服务器分别接收到不同的端口发来的数据
圆锥形nat.

如下如所示:

image_1bl03203113feqll1ha0nmr1mitm.png-27.4kB

圆锥形nat在转发同一主机同一端口号(ip和port都相同)发出的的数据时, 选用同一端口号进行转发. 所以可以利用这一点进行nat穿越
如图所示:

  • 在客户端: nat内主机192.168.1.100通过同一端口8000分别向5.6.7.8:56214和5.6.7.9:12540发出数据包. 地址对: { 192.168.1.100:8000 – 5.6.7.8:56214 } { 192.168.1.100:8000 – 5.6.7.9:12540 }
  • 在路由器: nat路由器1.2.3.4选用相同的的端口转发数据包(1.2.3.4:34594 ), 地址对: { 1.2.3.4:34594 – 5.6.7.8:56214 } { 1.2.3.4:34594 – 5.6.7.9:12540 }
  • 在服务器端: 两个服务器分别接收到相同的端口发来的数据

而圆锥形nat又分三种:

  • 完全圆锥型NAT : 同一主机同一端口号的数据都映射到nat路由器的同一端口, 任意外部主机向1.2.3.4:34594发送数据192.168.1.100:8000都能收到.
  • 受限圆锥型NAT :同一主机同一端口号的数据都映射到nat路由器的同一端口, 但必须内部主机192.168.1.100用8000向外部主机1.2.3.4发送一个数据报之后才能接受外部主机发来的数据
  • 端口受限圆锥型NAT : 同一主机同一端口号的数据都映射到nat路由器的同一端口, 但必须内部主机192.168.1.100用8000向外部主机1.2.3.4的34594端口发送一个数据报之后才能接受外部主机发来的数据

nat原理明白了, 接下来就可以设计如何nat穿越了.

image_1bl033glufm211471ra5f481eh413.png-38.3kB

分三步

  • 内部主机分别向处于外网的一台公共STUN服务器发送login信息, 报告自己的ip和端口 (图中的黑色)
  • 当服务器收到两台主机发来login后分别向两台主机发送对端的ip和端口 (图中的蓝色)
  • 两台内部主机用原先想服务器发login信息的端口向对端ip和端口通讯 (图中的粉色)
    原理明白了很简单

下面是我自己的一个实现

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

typedef struct sockaddr SA;

const unsigned short PORT = 38000;

const unsigned char LOGIN = 0x01;
const unsigned char PEER = 0x02;

void wait_login(int sock, struct sockaddr_in* remoteaddr, socklen_t* paddrlen)
{
int index = 0;

while (index < 2)
{
int n;
char buf[16];

if ((n = recvfrom(sock, buf, 16, 0, (SA*)&remoteaddr[index], paddrlen)) < 0)
{
perror("recvfrom");
exit(errno);
}
if (n != 1 || buf[0] != LOGIN)
continue; /* ignore it */
++index;
}
}

void send_peer(int sock, struct sockaddr_in* remoteaddr, int from, int to)
{
char ip[INET_ADDRSTRLEN];
char buf[1024];
buf[0] = PEER;

if (inet_ntop(AF_INET, &remoteaddr[from].sin_addr, ip, INET_ADDRSTRLEN) == NULL)
{
perror("inet_ntop");
exit(errno);
}
snprintf(buf + 1, 1023, "%s:%d", ip, ntohs(remoteaddr[from].sin_port));
printf("sending message: %s\n", buf + 1);
if (sendto(sock, buf, strlen(buf + 1) + 1, 0, (SA*)&remoteaddr[to], sizeof(remoteaddr[to])) < 0)
{
perror("sendto");
exit(errno);
}
}

int main()
{
int sock;
struct sockaddr_in localaddr;
struct sockaddr_in remoteaddr[2];
socklen_t addrlen = sizeof(remoteaddr[0]);

sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
perror("socket");
exit(errno);
}

bzero(&localaddr, sizeof(localaddr));
localaddr.sin_family = AF_INET;
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_port = htons(PORT);
if (bind(sock, (SA*)&localaddr, sizeof(localaddr)) < 0)
{
perror("bind");
exit(errno);
}

while (1)
{
wait_login(sock, remoteaddr, &addrlen);
send_peer(sock, remoteaddr, 0, 1);
send_peer(sock, remoteaddr, 1, 0);
}

return 0;
}

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#define max(a, b) ((a) > (b)?(a):(b))

const unsigned short PORT = 38000;

const unsigned char LOGIN = 0x01;
const unsigned char PEER = 0x02;
const unsigned char HELLO = 0x03;
const unsigned char MSG = 0x04;

typedef struct sockaddr SA;

int init_svraddr(const char* server, struct sockaddr_in* svrAddr, socklen_t len)
{
struct hostent* ent = gethostbyname(server);
if (ent == NULL)
{
fprintf(stderr, "gethostbyname:%s\n", hstrerror(h_errno));
return -1;
}

bzero(svrAddr, len);
svrAddr->sin_family = AF_INET;
svrAddr->sin_port = htons(PORT);
svrAddr->sin_addr = *(in_addr*)*ent->h_addr_list;
return 0;
}

int login(int sock, struct sockaddr_in* svrAddr, socklen_t len)
{
if (connect(sock, (SA*)svrAddr, len) < 0)
return -1;
if (write(sock, &LOGIN, sizeof(LOGIN)) < 0)
return -1;
return 0;
}

int get_peer_info(int sock, char* addrport, int len)
{
int i, j;
if ((i = read(sock, addrport, len)) < 0)
return -1;
if (*addrport != PEER)
return -1;

for (j = 0; j < i - 1; ++j)
addrport[j] = addrport[j + 1];
addrport[j] = '\0';
return 0;
}

int say_hello_peer(int sock, struct sockaddr* addr, socklen_t len)
{
if (connect(sock, addr, len) < 0)
return -1;
if (write(sock, &HELLO, sizeof(HELLO)) < 0)
return -1;
return 0;
}

int ptoap(char* str, struct sockaddr_in* addr, socklen_t len)
{
char* p;
bzero(addr, len);
addr->sin_family = AF_INET;

p = strchr(str, ':');
*p = '\0';
if (inet_pton(AF_INET, str, &addr->sin_addr) < 0)
return -1;
addr->sin_port = htons(atoi(p + 1));
return 0;
}

const char* SERVER = "198.56.248.214";

int main()
{
int sock;
char addrport[256];
struct sockaddr_in svrAddr;
struct sockaddr_in peeraddr;

sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
perror("socket");
exit(errno);
}

if (init_svraddr(SERVER, &svrAddr, sizeof(svrAddr)) == -1)
exit(-1);

printf("Sending login\n");
if (login(sock, &svrAddr, sizeof(svrAddr)) == -1)
{
perror("login");
exit(errno);
}

printf("Getting peer info\n");
if (get_peer_info(sock, addrport, 256) == -1)
{
perror("get_peer_info");
exit(errno);
}
printf("Peer info: %s\n", addrport);

if (ptoap(addrport, &peeraddr, sizeof(peeraddr)) == -1)
{
perror("ptoap");
exit(errno);
}

if (say_hello_peer(sock, (SA*)&peeraddr, sizeof(peeraddr)) == -1)
{
perror("say_hello_peer");
exit(errno);
}

while (true)
{
fd_set sockstdin;
int maxFd;
int n;
char buf[4096];

FD_ZERO(&sockstdin);
FD_SET(STDIN_FILENO, &sockstdin);
FD_SET(sock, &sockstdin);
maxFd = max(sock, STDIN_FILENO);

if (select(maxFd + 1, &sockstdin, NULL, NULL, NULL) < 0)
{
perror("select");
exit(errno);
}

if (FD_ISSET(STDIN_FILENO, &sockstdin))
{

if ((n = read(STDIN_FILENO, buf, 4096)) < 0)
{
perror("read");
exit(errno);
}
else if (n == 0)
{
exit(0); /* exit normally */
}
if (write(sock, buf, n) < 0)
{
perror("sendto");
exit(errno);
}
}
if (FD_ISSET(sock, &sockstdin))
{
if ((n = read(sock, buf, 4096)) < 0)
{
perror("read");
exit(errno);
}
if (write(STDOUT_FILENO, buf, n) < 0)
{
perror("write");
exit(errno);
}
}
}

return 0;
}

Proudly powered by Hexo and Theme by Hacker
© 2021 wastecat