我們知道無論是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);
}
}