详解bind在网络编程中的应用

我们知道无论是UDP还是TCP,socket都会与一个本地的IP和端口绑定,这个IP和端口称之为socket的源地址和源端口。

而客户端利用socket去发送数据时,很少会去考虑这个源地址和源端口到底是什么,我们更关心的是它的目的地址和端口。往往只有在服务器端需要监听的时候,才去考虑这个源端口。所以我们往往在服务器端监听的时候才会用bind。当我们bind之后,内核就会将这个socket锁定到我们设定的地址和端口上。事实上,在客户端也可以先通过bind指定发送数据的端口,只是,如果不bind,则内核会自动分配发送端口罢了。

bind的时候,函数参数中的端口填自己将要绑定的端口就行。IP地址需要填本机的IP,也可以用宏INADDR_ANY代替,用这个宏就可以不用查找本机的IP,它就可以代替本机的IP。

此外,当bind的参数中端口地址为0的时就是由内核分配端口。这样可以避免端口地址重复的问题。bind对于源ip地址也同样具备这种处理方式,当系统具有多IP(多网卡)时,把bind函数中的ip参数置0时,就是由内核自己选择分配IP。之前提到的INADDR_ANY的值其实就是0。


下面是一个例子,其中客户端为TI NDK对应的DSP程序:

#include <stdio.h>
#include <netmain.h>
#include <_stack.h>

#define SEND_MAX_SIZE 512
char sendBuffer[SEND_MAX_SIZE];
char recvBuffer[1500];
char *UnicastAddr = "192.168.1.10";
// PC address


void udp_send()
{
    SOCKET   send = INVALID_SOCKET;     // Sender socket. 
    struct   sockaddr_in sout1;         // Sender socket address structure
    int sentCnt;
 int i;

    // Allocate the file environment for this task
    fdOpenSession( TaskSelf() );

    // Create the send socket
    send = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if( send == INVALID_SOCKET )
        goto leave;

    // Send socket: set Port = 5000, IP destination address = 0
    bzero( &sout1, sizeof(struct sockaddr_in) );
    sout1.sin_family = AF_INET;
    sout1.sin_len    = sizeof( sout1 );
    sout1.sin_port   = htons(5000);

    // Bind send socket
 /*设置发送端口5000*/
    if ( bind( send, (PSA) &sout1, sizeof(sout1) ) < 0 )
        {
        printf("Send: %d",fdError());
        goto leave;
        }

for(i=0;i<SEND_MAX_SIZE;i++)
{
sendBuffer[i]=i%128;
}
        
    for(;;)
    {
         sout1.sin_addr.s_addr = inet_addr(UnicastAddr); // PC address is the destination
         sout1.sin_port = htons(4000); // 设置PC端口


        // Send to PC every 1 ms
         do
         {
             TaskSleep(1);
             sentCnt = sendto( send, sendBuffer, SEND_MAX_SIZE, 0, (struct sockaddr *)&sout1, sizeof(sout1) );
         } while (sentCnt < 0);
      
    }

leave:
    // We only get here on a fatal error - close the sockets
    if( send != INVALID_SOCKET )
        fdClose( send );    
    printf("Fatal Error\n");
    // This task is killed by the system - here, we block
    TaskBlock( TaskSelf() );
}


服务器为VC++程序:

{

#define RECV_MAX_SIZE 8192
unsigned char       pBuf[RECV_MAX_SIZE] ;
FILE *fp_binary;
int recv_buf_size = RECV_MAX_SIZE;
WORD wVersionRequested;
WSADATA wsaData;
int err;
int rcv_cnt=0;
SOCKADDR_IN addrSrv;
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
SOCKET sockSrv;


fp_binary = fopen(".\\fifo_data.dat","wb");

wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
goto leave;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 ) {
goto leave; 
}

sockSrv=socket(AF_INET,SOCK_DGRAM,0);
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(4000);


//在4000端口监听
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
while(!pDlg->KillChildThread)
{

rcv_cnt=recvfrom(sockSrv,(char *)pBuf,RECV_MAX_SIZE,0,(SOCKADDR*)&addrClient,&len);
fwrite(pBuf,4,rcv_cnt/4,fp_binary);
}

leave:
if( sockSrv >= 0 )
closesocket( sockSrv );
    WSACleanup();
pDlg->m_list_display.InsertString(0,"FpgaFifoReadThread 结束!");

if (fp_binary)
{
fclose(fp_binary);
}
}


发布了26 篇原创文章 · 获赞 15 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章