我们知道无论是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);
}
}