詳解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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章