今天的程序员普遍遵循这样的接口设计原则:通过不同的接口名和参数列表准确表达不同的功能。
这似乎是理所当然的,然而上古时代却并非如此,比如Netbios协议整个协议的接口只有一个函数、一个参数!
当初是基于什么原则这样设计不晓得,但它确实真真实实地存在过,最初是在windows 2000上实现的,到了windows vista就被淘汰。
我之所以用到这个东西是为了取得局域网上的机器名,代码如下:
- //取得MACHNAME
- STATE getmachname(char * ip,char * machname,int machnamelen)
- {
- if(machnamelen<16)
- {
- return -1;
- }
-
- //以下使用socket
- hostent * phost;
- unsigned long addr;
- if(INADDR_NONE==(addr=inet_addr(ip)))
- return -1;
- if(NULL!=(phost=gethostbyaddr((char *)&addr,4,PF_INET)))
- {
- if((int)strlen(phost->h_name)>=machnamelen)
- return -1;
- else
- {
- strcpy(machname,phost->h_name);
- return 1;
- }
- }
-
- //以下使用NetBIOS
- char ncb_buffer[sizeof(ADAPTER_STATUS)+256*sizeof(NAME_BUFFER)];
- UCHAR ret;
- NCB ncb;
- ADAPTER_STATUS * adapter_status;
- NAME_BUFFER * name_buffer;
- int lanacount;
-
- memset(&ncb,0,sizeof(NCB));
- memset(ncb_buffer,0xa3,sizeof(ADAPTER_STATUS)+256*sizeof(NAME_BUFFER));
-
- adapter_status=(ADAPTER_STATUS *)ncb_buffer;
- name_buffer=(NAME_BUFFER *)(ncb_buffer+sizeof(ADAPTER_STATUS));
-
- ncb.ncb_lana_num=0;
- ncb.ncb_lsn=0;
- ncb.ncb_num=0;
- ncb.ncb_command=NCBRESET;
- // if(NRC_GOODRET!=(ret=Netbios(&ncb)))
- {
- // return -2;
- }
-
-
- for(lanacount=0;lanacount<=0;lanacount++)
- {
- memset(&ncb,0,sizeof(NCB));
- memset(ncb_buffer,0xa3,sizeof(ADAPTER_STATUS)+256*sizeof(NAME_BUFFER));
- //设置输入
- ncb.ncb_command=NCBASTAT;
- ncb.ncb_buffer=(unsigned char *)ncb_buffer;
- ncb.ncb_length=sizeof(ADAPTER_STATUS)+256*sizeof(NAME_BUFFER);
- memset((char *)ncb.ncb_callname,' ',15);
- ncb.ncb_callname[15]='\0';
- memcpy((char *)ncb.ncb_callname,ip,strlen(ip));
-
- //预先设置输出(无意义)
- name_buffer->name[0]='\0';
-
- ncb.ncb_lana_num=(UCHAR)lanacount;
- if(NRC_GOODRET==(ret=Netbios(&ncb)))
- {
- break;
- }
- else
- {
- // showret(ret);
- }
- }
- if(0
- {
- return -3;
- }
-
- memcpy(machname,name_buffer[0].name,16);
- return 1;
- }
因为取机器名比较困难,所以我同时使用了socket函数和Netbios。具体代码无关紧要了,因为早已经过时,主要目的是看看Netbios接口有多令人震惊。
Netbios接口如下:
- UCHAR Netbios(
- PNCB pncb
- );
好简洁啊!真是令人赞叹!
只有一个参数,是个指针,指向这个:
- typedef struct _NCB {
- UCHAR ncb_command;
- UCHAR ncb_retcode;
- UCHAR ncb_lsn;
- UCHAR ncb_num;
- PUCHAR ncb_buffer;//这是个指针
- WORD ncb_length;
- UCHAR ncb_callname[NCBNAMSZ];
- UCHAR ncb_name[NCBNAMSZ];
- UCHAR ncb_rto;
- UCHAR ncb_sto;
- void()(_NCB *) * ncb_post;//这里又是一个指针
- UCHAR ncb_lana_num;
- UCHAR ncb_cmd_cplt;
- #if ...
- UCHAR ncb_reserve[18];
- #else
- UCHAR ncb_reserve[10];
- #endif
- HANDLE ncb_event;
- } NCB, *PNCB;
这个结构里面还包括一个指向这种结构的指针,也就是可以无限级联下去。
第一个成员ncb_command是命令,我大概数了一下,有26种命令,也就是这个结构有26种解释。
每种命令仅仅使用其它成员的一小部分。其中ncb_buffer指针指向的结构视命令不同而不同。比如某个命令要求ncb_buffer指向这个结构:
- typedef struct _SESSION_HEADER {
- UCHAR sess_name;
- UCHAR num_sess;
- UCHAR rcv_dg_outstanding;
- UCHAR rcv_any_outstanding;
- } SESSION_HEADER, *PSESSION_HEADER;
类似的结构体有八个。
虽说按照说明书往下啃是可以理解全部的,但确实有一种啃单片机手册的感觉。
这个东西被淘汰了,该!
(这里是结束)