void NetReceive(volatile uchar * inpkt, int len)
来源:互联网 发布:淘宝网有没有海外版 编辑:程序博客网 时间:2024/04/30 20:10
void
NetReceive(volatile uchar * inpkt, int len)
{
Ethernet_t *et;
IP_t *ip;
ARP_t *arp;
IPaddr_t tmp;
int x;
uchar *pkt;
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
int iscdp;
#endif
ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
#ifdef ET_DEBUG
printf("packet received\n");
#endif
NetRxPkt = inpkt;
NetRxPktLen = len;
et = (Ethernet_t *)inpkt;
/* too small packet? */
if (len < ETHER_HDR_SIZE)
return;
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
/* keep track if packet is CDP */
iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
#endif
myvlanid = ntohs(NetOurVLAN);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
mynvlanid = ntohs(NetOurNativeVLAN);
if (mynvlanid == (ushort)-1)
mynvlanid = VLAN_NONE;
x = ntohs(et->et_protlen);
#ifdef ET_DEBUG
printf("packet received\n");
#endif
if (x < 1514) { //判断协议
/*
* Got a 802 packet. Check the other protocol field.
*/
x = ntohs(et->et_prot);
ip = (IP_t *)(inpkt + E802_HDR_SIZE);
len -= E802_HDR_SIZE;
} else if (x != PROT_VLAN) { /* normal packet */ //不使用虚拟网
ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
len -= ETHER_HDR_SIZE;
} else { /* VLAN packet */
VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
#ifdef ET_DEBUG
printf("VLAN packet received\n");
#endif
/* too small packet? */
if (len < VLAN_ETHER_HDR_SIZE)
return;
/* if no VLAN active */
if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
&& iscdp == 0
#endif
)
return;
cti = ntohs(vet->vet_tag);
vlanid = cti & VLAN_IDMASK;
x = ntohs(vet->vet_type);
ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
len -= VLAN_ETHER_HDR_SIZE;
}
#ifdef ET_DEBUG
printf("Receive from protocol 0x%x\n", x);
#endif
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
if (iscdp) {
CDPHandler((uchar *)ip, len);
return;
}
#endif
if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
if (vlanid == VLAN_NONE)
vlanid = (mynvlanid & VLAN_IDMASK);
/* not matched? */
if (vlanid != (myvlanid & VLAN_IDMASK))
return;
}
switch (x) { //-----------------------判断协议
case PROT_ARP: //---------------使用ARP
/*
* We have to deal with two types of ARP packets:
* - REQUEST packets will be answered by sending our
* IP address - if we know it.
* - REPLY packates are expected only after we asked
* for the TFTP server's or the gateway's ethernet
* address; so if we receive such a packet, we set
* the server ethernet address
*/
#ifdef ET_DEBUG
puts ("Got ARP\n");
#endif
arp = (ARP_t *)ip;
if (len < ARP_HDR_SIZE) { //长度
printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
return;
}
if (ntohs(arp->ar_hrd) != ARP_ETHER) { //硬件地址类型
return;
}
if (ntohs(arp->ar_pro) != PROT_IP) { //协议
return;
}
if (arp->ar_hln != 6) { //硬件地址长度
return;
}
if (arp->ar_pln != 4) { //ip地址长度
return;
}
if (NetOurIP == 0) { //本地ip
return;
}
if (NetReadIP(&arp->ar_data[16]) != NetOurIP) { //是否是发给本机的
return;
}
switch (ntohs(arp->ar_op)) { //--------------------------判断操作类型
case ARPOP_REQUEST: /* reply with our IP address */
#ifdef ET_DEBUG
puts ("Got ARP REQUEST, return our IP\n");
#endif
pkt = (uchar *)et;
pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
arp->ar_op = htons(ARPOP_REPLY);
memcpy (&arp->ar_data[10], &arp->ar_data[0], 6);
NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
memcpy (&arp->ar_data[ 0], NetOurEther, 6);
NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
(void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
return;
case ARPOP_REPLY: /* arp reply */
/* are we waiting for a reply */
if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC) //等待的目标ip和目标mac指针
break;
#ifdef ET_DEBUG
printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
arp->ar_data[0], arp->ar_data[1],
arp->ar_data[2], arp->ar_data[3],
arp->ar_data[4], arp->ar_data[5]);
#endif
tmp = NetReadIP(&arp->ar_data[6]); //读ip
/* matched waiting packet's address */
if (tmp == NetArpWaitReplyIP) { //等待返回地址
#ifdef ET_DEBUG
puts ("Got it\n");
#endif
/* save address for later use */
memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6); //保存mac地址
#ifdef CONFIG_NETCONSOLE
(*packetHandler)(0,0,0,0);
#endif
/* modify header, and transmit it */
memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6); //保存到数据报
(void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize); //发送ICMP请求
/* no arp request pending now */
NetArpWaitPacketIP = 0;
NetArpWaitTxPacketSize = 0;
NetArpWaitPacketMAC = NULL;
}
return;
default:
#ifdef ET_DEBUG
printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
#endif
return;
}
break;
case PROT_RARP:
#ifdef ET_DEBUG
puts ("Got RARP\n");
#endif
arp = (ARP_t *)ip;
if (len < ARP_HDR_SIZE) {
printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
return;
}
if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
(ntohs(arp->ar_hrd) != ARP_ETHER) ||
(ntohs(arp->ar_pro) != PROT_IP) ||
(arp->ar_hln != 6) || (arp->ar_pln != 4)) {
puts ("invalid RARP header\n");
} else {
NetCopyIP(&NetOurIP, &arp->ar_data[16]);
if (NetServerIP == 0)
NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
memcpy (NetServerEther, &arp->ar_data[ 0], 6);
(*packetHandler)(0,0,0,0);
}
break;
case PROT_IP: //----------------使用IP
#ifdef ET_DEBUG
puts ("Got IP\n");
#endif
if (len < IP_HDR_SIZE) {
debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
return;
}
if (len < ntohs(ip->ip_len)) {
printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
return;
}
len = ntohs(ip->ip_len);
#ifdef ET_DEBUG
printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
#endif
if ((ip->ip_hl_v & 0xf0) != 0x40) {
return;
}
if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
return;
}
if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
puts ("checksum bad\n");
return;
}
tmp = NetReadIP(&ip->ip_dst);
if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
return;
}
/*
* watch for ICMP host redirects
*
* There is no real handler code (yet). We just watch
* for ICMP host redirect messages. In case anybody
* sees these messages: please contact me
* (wd@denx.de), or - even better - send me the
* necessary fixes :-)
*
* Note: in all cases where I have seen this so far
* it was a problem with the router configuration,
* for instance when a router was configured in the
* BOOTP reply, but the TFTP server was on the same
* subnet. So this is probably a warning that your
* configuration might be wrong. But I'm not really
* sure if there aren't any other situations.
*/
if (ip->ip_p == IPPROTO_ICMP) { //-----------------ICMP
ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
switch (icmph->type) {
case ICMP_REDIRECT:
if (icmph->code != ICMP_REDIR_HOST)
return;
puts (" ICMP Host Redirect to ");
print_IPaddr(icmph->un.gateway);
putc(' ');
return;
#if (CONFIG_COMMANDS & CFG_CMD_PING)
case ICMP_ECHO_REPLY:
/*
* IP header OK. Pass the packet to the current handler.
*/
/* XXX point to ip packet */
(*packetHandler)((uchar *)ip, 0, 0, 0);
return;
#endif
default:
return;
}
} else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
return;
}
#ifdef CONFIG_UDP_CHECKSUM
if (ip->udp_xsum != 0) {
ulong xsum;
ushort *sumptr;
ushort sumlen;
xsum = ip->ip_p;
xsum += (ntohs(ip->udp_len));
xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_src) >> 0) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst) >> 0) & 0x0000ffff;
sumlen = ntohs(ip->udp_len);
sumptr = (ushort *) &(ip->udp_src);
while (sumlen > 1) {
ushort sumdata;
sumdata = *sumptr++;
xsum += ntohs(sumdata);
sumlen -= 2;
}
if (sumlen > 0) {
ushort sumdata;
sumdata = *(unsigned char *) sumptr;
sumdata = (sumdata << 8) & 0xff00;
xsum += sumdata;
}
while ((xsum >> 16) != 0) {
xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
}
if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
printf(" UDP wrong checksum %08x %08x\n", xsum, ntohs(ip->udp_xsum));
return;
}
}
#endif
#ifdef CONFIG_NETCONSOLE
nc_input_packet((uchar *)ip +IP_HDR_SIZE,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - 8);
#endif
/*
* IP header OK. Pass the packet to the current handler.
*/
(*packetHandler)((uchar *)ip +IP_HDR_SIZE,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - 8);
break;
}
}
NetReceive(volatile uchar * inpkt, int len)
{
Ethernet_t *et;
IP_t *ip;
ARP_t *arp;
IPaddr_t tmp;
int x;
uchar *pkt;
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
int iscdp;
#endif
ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
#ifdef ET_DEBUG
printf("packet received\n");
#endif
NetRxPkt = inpkt;
NetRxPktLen = len;
et = (Ethernet_t *)inpkt;
/* too small packet? */
if (len < ETHER_HDR_SIZE)
return;
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
/* keep track if packet is CDP */
iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
#endif
myvlanid = ntohs(NetOurVLAN);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
mynvlanid = ntohs(NetOurNativeVLAN);
if (mynvlanid == (ushort)-1)
mynvlanid = VLAN_NONE;
x = ntohs(et->et_protlen);
#ifdef ET_DEBUG
printf("packet received\n");
#endif
if (x < 1514) { //判断协议
/*
* Got a 802 packet. Check the other protocol field.
*/
x = ntohs(et->et_prot);
ip = (IP_t *)(inpkt + E802_HDR_SIZE);
len -= E802_HDR_SIZE;
} else if (x != PROT_VLAN) { /* normal packet */ //不使用虚拟网
ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
len -= ETHER_HDR_SIZE;
} else { /* VLAN packet */
VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
#ifdef ET_DEBUG
printf("VLAN packet received\n");
#endif
/* too small packet? */
if (len < VLAN_ETHER_HDR_SIZE)
return;
/* if no VLAN active */
if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
&& iscdp == 0
#endif
)
return;
cti = ntohs(vet->vet_tag);
vlanid = cti & VLAN_IDMASK;
x = ntohs(vet->vet_type);
ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
len -= VLAN_ETHER_HDR_SIZE;
}
#ifdef ET_DEBUG
printf("Receive from protocol 0x%x\n", x);
#endif
#if (CONFIG_COMMANDS & CFG_CMD_CDP)
if (iscdp) {
CDPHandler((uchar *)ip, len);
return;
}
#endif
if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
if (vlanid == VLAN_NONE)
vlanid = (mynvlanid & VLAN_IDMASK);
/* not matched? */
if (vlanid != (myvlanid & VLAN_IDMASK))
return;
}
switch (x) { //-----------------------判断协议
case PROT_ARP: //---------------使用ARP
/*
* We have to deal with two types of ARP packets:
* - REQUEST packets will be answered by sending our
* IP address - if we know it.
* - REPLY packates are expected only after we asked
* for the TFTP server's or the gateway's ethernet
* address; so if we receive such a packet, we set
* the server ethernet address
*/
#ifdef ET_DEBUG
puts ("Got ARP\n");
#endif
arp = (ARP_t *)ip;
if (len < ARP_HDR_SIZE) { //长度
printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
return;
}
if (ntohs(arp->ar_hrd) != ARP_ETHER) { //硬件地址类型
return;
}
if (ntohs(arp->ar_pro) != PROT_IP) { //协议
return;
}
if (arp->ar_hln != 6) { //硬件地址长度
return;
}
if (arp->ar_pln != 4) { //ip地址长度
return;
}
if (NetOurIP == 0) { //本地ip
return;
}
if (NetReadIP(&arp->ar_data[16]) != NetOurIP) { //是否是发给本机的
return;
}
switch (ntohs(arp->ar_op)) { //--------------------------判断操作类型
case ARPOP_REQUEST: /* reply with our IP address */
#ifdef ET_DEBUG
puts ("Got ARP REQUEST, return our IP\n");
#endif
pkt = (uchar *)et;
pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
arp->ar_op = htons(ARPOP_REPLY);
memcpy (&arp->ar_data[10], &arp->ar_data[0], 6);
NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
memcpy (&arp->ar_data[ 0], NetOurEther, 6);
NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
(void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
return;
case ARPOP_REPLY: /* arp reply */
/* are we waiting for a reply */
if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC) //等待的目标ip和目标mac指针
break;
#ifdef ET_DEBUG
printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
arp->ar_data[0], arp->ar_data[1],
arp->ar_data[2], arp->ar_data[3],
arp->ar_data[4], arp->ar_data[5]);
#endif
tmp = NetReadIP(&arp->ar_data[6]); //读ip
/* matched waiting packet's address */
if (tmp == NetArpWaitReplyIP) { //等待返回地址
#ifdef ET_DEBUG
puts ("Got it\n");
#endif
/* save address for later use */
memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6); //保存mac地址
#ifdef CONFIG_NETCONSOLE
(*packetHandler)(0,0,0,0);
#endif
/* modify header, and transmit it */
memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6); //保存到数据报
(void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize); //发送ICMP请求
/* no arp request pending now */
NetArpWaitPacketIP = 0;
NetArpWaitTxPacketSize = 0;
NetArpWaitPacketMAC = NULL;
}
return;
default:
#ifdef ET_DEBUG
printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
#endif
return;
}
break;
case PROT_RARP:
#ifdef ET_DEBUG
puts ("Got RARP\n");
#endif
arp = (ARP_t *)ip;
if (len < ARP_HDR_SIZE) {
printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
return;
}
if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
(ntohs(arp->ar_hrd) != ARP_ETHER) ||
(ntohs(arp->ar_pro) != PROT_IP) ||
(arp->ar_hln != 6) || (arp->ar_pln != 4)) {
puts ("invalid RARP header\n");
} else {
NetCopyIP(&NetOurIP, &arp->ar_data[16]);
if (NetServerIP == 0)
NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
memcpy (NetServerEther, &arp->ar_data[ 0], 6);
(*packetHandler)(0,0,0,0);
}
break;
case PROT_IP: //----------------使用IP
#ifdef ET_DEBUG
puts ("Got IP\n");
#endif
if (len < IP_HDR_SIZE) {
debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
return;
}
if (len < ntohs(ip->ip_len)) {
printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
return;
}
len = ntohs(ip->ip_len);
#ifdef ET_DEBUG
printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
#endif
if ((ip->ip_hl_v & 0xf0) != 0x40) {
return;
}
if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
return;
}
if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
puts ("checksum bad\n");
return;
}
tmp = NetReadIP(&ip->ip_dst);
if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
return;
}
/*
* watch for ICMP host redirects
*
* There is no real handler code (yet). We just watch
* for ICMP host redirect messages. In case anybody
* sees these messages: please contact me
* (wd@denx.de), or - even better - send me the
* necessary fixes :-)
*
* Note: in all cases where I have seen this so far
* it was a problem with the router configuration,
* for instance when a router was configured in the
* BOOTP reply, but the TFTP server was on the same
* subnet. So this is probably a warning that your
* configuration might be wrong. But I'm not really
* sure if there aren't any other situations.
*/
if (ip->ip_p == IPPROTO_ICMP) { //-----------------ICMP
ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
switch (icmph->type) {
case ICMP_REDIRECT:
if (icmph->code != ICMP_REDIR_HOST)
return;
puts (" ICMP Host Redirect to ");
print_IPaddr(icmph->un.gateway);
putc(' ');
return;
#if (CONFIG_COMMANDS & CFG_CMD_PING)
case ICMP_ECHO_REPLY:
/*
* IP header OK. Pass the packet to the current handler.
*/
/* XXX point to ip packet */
(*packetHandler)((uchar *)ip, 0, 0, 0);
return;
#endif
default:
return;
}
} else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
return;
}
#ifdef CONFIG_UDP_CHECKSUM
if (ip->udp_xsum != 0) {
ulong xsum;
ushort *sumptr;
ushort sumlen;
xsum = ip->ip_p;
xsum += (ntohs(ip->udp_len));
xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_src) >> 0) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst) >> 0) & 0x0000ffff;
sumlen = ntohs(ip->udp_len);
sumptr = (ushort *) &(ip->udp_src);
while (sumlen > 1) {
ushort sumdata;
sumdata = *sumptr++;
xsum += ntohs(sumdata);
sumlen -= 2;
}
if (sumlen > 0) {
ushort sumdata;
sumdata = *(unsigned char *) sumptr;
sumdata = (sumdata << 8) & 0xff00;
xsum += sumdata;
}
while ((xsum >> 16) != 0) {
xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
}
if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
printf(" UDP wrong checksum %08x %08x\n", xsum, ntohs(ip->udp_xsum));
return;
}
}
#endif
#ifdef CONFIG_NETCONSOLE
nc_input_packet((uchar *)ip +IP_HDR_SIZE,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - 8);
#endif
/*
* IP header OK. Pass the packet to the current handler.
*/
(*packetHandler)((uchar *)ip +IP_HDR_SIZE,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - 8);
break;
}
}
- void NetReceive(volatile uchar * inpkt, int len)
- static void PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
- 仅从代码可读性来看void fun(const void *p, int len)中const的重要性
- msync(void *addr,size_t len, int flags) 函数的使用问题
- msync(void *addr,size_t len, int flags) 函数的使用问题
- recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);/函数简单了解
- saturate_cast<uchar>(int v)的作用
- void (*f(int, void (*)(int)))(int)
- void (*Pfun(int, void(*Qfun)(int))) (int)
- (C)理解 #define write(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
- 理解(*(void(*)())0)()和void (*signal(int, void(*)(int)))(int)
- void (*func)(int)和void (*func)(void)
- int substr( char dst[], char src[], int start, int len )
- winsock:int errorcode=>buf[len]
- int main (void)
- int getchar(void);
- void assert (int expression)
- typedef int (init_fnc_t) (void);
- 基于pca的人脸识别
- Linux常用的网络命令
- MSTP配置
- 经典SQL语句大全!
- liux cp scp命令
- void NetReceive(volatile uchar * inpkt, int len)
- 寻找最大的第K个数
- Pascal's Triangle
- android performance analyse
- Android调用天气预报的WebService简单例子
- StatSvn导出SVN代码量报告
- Win7无法访问2003server中的TFS,并且无法访问共享文件夹
- OpenCV函数cvWatershed图像分割中分水岭算法
- const函数参数优点