用Socket在局域网内进行广播

240 篇文章 2 订阅

服务器和客户机采用Socket编程。
问题1:服务器进入侦听状态,但是此时客户端并不知道服务器的地址。我该如何做?

问题2:我想使客户端先发出一个广播,服务器接受广播后给客户机发送自己的Ip等信息。
接着再建立Socket通讯。这样对吗?

问题3:是不是进行广播必须是数据报SOCK_DGRAM   

问题4:是不是通讯的双方必须都是数据流或数据报?如果服务器是数据流SOCK_STREAM套接字,而客户机是数据报套接字就不能够通讯?

1、用广播(或组播)方式,客户端不需道服务器的地址,初始化时用程序建立一个新的广播地址。
2、用广播(或组播)方式,可直接收发数据。不用侦听。
3、是;
4、只要是数据就行。
例子:

//   MSGSocket.cpp   :   implementation   file 
// 

#include   "stdafx.h " 
//#include   "AV8Rcvr.h " 
#include   "MSGSocket.h " 

#ifdef   _DEBUG 
#define   new   DEBUG_NEW 
#undef   THIS_FILE 
static   char   THIS_FILE[]   =   __FILE__; 
#endif 

/ 
//   CMSGSocket 

CMSGSocket::CMSGSocket() 
{ 
bForceNoLoopback   =   FALSE; 
bDataReceived   =   false; /*   Variable   defined   for   this   project.   Not   necessarily   part   of   CMsocket   */ 
number=0; 
for(int   i=0;i <40;i++) 
{ 
ready[i]=false; 
} 
number=0; 
newfile=false; 
receivenumber=0; 
filename= " "; 


} 

CMSGSocket::~CMSGSocket() 
{ 
} 


//   Do   not   edit   the   following   lines,   which   are   needed   by   ClassWizard. 
#if   0 
BEGIN_MESSAGE_MAP(CMSGSocket,   CSocket) 
//{{AFX_MSG_MAP(CMSGSocket) 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
#endif //   0 

/ 
//   CMSGSocket   member   functions 
BOOL   CMSGSocket::CreateSocket(LPCTSTR   strGroupIP,   UINT   nGroupPort) 
{ 
/*   Create   socket   for   receiving   packets   from   multicast   group   */ 
LeaveGroup(); 
//if(!Create(nGroupPort,   SOCK_DGRAM,   FD_READ|FD_WRITE))     //CAsyncSocket 
if(!Create(nGroupPort,   SOCK_DGRAM,   NULL))     //CSocket 
{ 
AfxMessageBox( "建立连接时出错,检查该频道是否已被别的窗口占用! "); 
return   FALSE; 
} 

BOOL   bMultipleApps   =   TRUE; /*   allow   reuse   of   local   port   if   needed   */ 
SetSockOpt(SO_REUSEADDR,   (void*)&bMultipleApps,   sizeof(BOOL),   SOL_SOCKET); 

/*   Fill   m_saHostGroup_in   for   sending   datagrams   */ 
memset(&m_saHostGroup,   0,   sizeof(m_saHostGroup)); 
m_saHostGroup.sin_family   =   AF_INET; 
m_saHostGroup.sin_addr.s_addr   =   inet_addr(strGroupIP); 
m_saHostGroup.sin_port   =   htons((USHORT)nGroupPort); 

/*   Join   the   multicast   group   */ 
m_mrMReq.imr_multiaddr.s_addr   =   inet_addr(strGroupIP); /*   group   addr   */  
 m_mrMReq.imr_interface.s_addr   =   htons(INADDR_ANY); /*   use   default   */   
if(setsockopt(m_hSocket,   IPPROTO_IP,   IP_ADD_MEMBERSHIP,   (char   FAR   *)&m_mrMReq,   sizeof(m_mrMReq))   <   0) 
{ 
AfxMessageBox( "CreateReceivingSocket   failed "); 
return   FALSE; 
} 

return   TRUE; 
} 

void   CMSGSocket::OnReceive(int   nErrorCode) 
{ 
::SetActiveWindow(AfxGetApp()-> m_pMainWnd-> m_hWnd); 
//AfxMessageBox( "MSG收到数据! "); 
//return; 
int   nError   =   ReceiveFrom   (&msg_commanddata,sizeof(csock_data),   m_strSendersIP,   m_nSendersPort); 

if(nError   ==   SOCKET_ERROR) 
AfxMessageBox( "Error   receiving   data   from   the   host   group "); 
else 
{ 
if   (!bForceNoLoopback   ||   (bForceNoLoopback   &&   !(m_strSendersIP   ==   m_strLocalIP   &&   m_nSendersPort   ==   m_nLocalPort))) 
{ 
//lyksetdata1(3); 
//AfxMessageBox( "MSG收到数据! "); 
::PostMessage(GetActiveWindow(   ),WM_COMMAND,WM_RECEIVEMSG,(LPARAM)0); 
} 
} 
CSocket::OnReceive(nErrorCode);   
} 


BOOL   CMSGSocket::LeaveGroup() 
{ 
if(setsockopt   (m_hSocket,   IPPROTO_IP,   IP_DROP_MEMBERSHIP,   (char   FAR   *)&m_mrMReq,   sizeof(m_mrMReq))   <   0) 
return   FALSE; 

Close(); //   Close   receving   socket 
return   TRUE; 
} 

/* 
BOOL   CMSGSocket::Send(const   void*   strMessage,   int   nSize) 
{ 
//CString   str=strMessage; 
//AfxMessageBox(str); 

if(SendTo(strMessage,   nSize,   (SOCKADDR*)&m_saHostGroup,   sizeof(SOCKADDR),   0)   ==   SOCKET_ERROR) 
return   FALSE; 
else 
return   TRUE; 
} 
*/ 
BOOL   CMSGSocket::Send(csock_data   m_data1) 
{ 

if(SendTo(&m_data1,   sizeof(csock_data),   (SOCKADDR*)&m_saHostGroup,   sizeof(SOCKADDR),   0)   ==   SOCKET_ERROR) 
{ 
        return   FALSE; 
} 
else 
{ 
//AfxMessageBox( "MSGSend! "); 
return   TRUE; 
} 
} 

BOOL   CMSGSocket::TextSend(CString   str) 
{ 
CString   st=str; 
st+= "/@&/ "; 
//BOOL   bo=Send(st,   st.GetLength()+1); 
return   0; 
} 

BOOL   CMSGSocket::GetMaker(void) 
{ 
return   bDataReceived; 
} 

void   CMSGSocket::SetMaker(BOOL   da) 
{ 
bDataReceived=da; 
//ready[number]==da; 
} 

void   CMSGSocket::Init(void) 
{ 
bForceNoLoopback   =   FALSE; 
bDataReceived   =   false; /*   Variable   defined   for   this   project.   Not   necessarily   part   of   CMSGSocket   */ 
number=0; 
for(int   i=0;i <40;i++) 
{ 
ready[i]=false; 
} 
} 


BOOL   CMSGSocket::SendFile(CString   filename) 
{ 
return   0; 
} 

void   CMSGSocket::ReadFile() 
{ 

} 

BOOL   CMSGSocket::SendData(SOCKET_STREAM_FILE_INFO   m_data1) 
{ 
//AfxMessageBox( "send........ "); 
if(SendTo(&m_data1,   sizeof(SOCKET_STREAM_FILE_INFO),   (SOCKADDR*)&m_saHostGroup,   sizeof(SOCKADDR),   0)   ==   SOCKET_ERROR) 
{ 
//AfxMessageBox( "send   false "); 
        return   FALSE; 
} 
else 
{ 
//AfxMessageBox( "send   ok "); 
return   TRUE; 
} 
}


 

#if   !defined(AFX_MSGSocket_H__257F140C_C139_4112_BACA_2C16C0F155B8__INCLUDED_) 
#define   AFX_MSGSocket_H__257F140C_C139_4112_BACA_2C16C0F155B8__INCLUDED_ 

#if   _MSC_VER   >   1000 
#pragma   once 
#endif   //   _MSC_VER   >   1000 
//   MSGSocket.h   :   header   file 
// 

/ 
//   CMSGSocket   command   target 

class   CMSGSocket   :   public   CSocket 
{ 
//   Attributes 
public: 
char   m_strBuffer[32768]; 
char   m_strBuffer1[32768]; 
char   m_strBuffer2[32768]; //   Receiving   buffer   for   the   packet   that   has   arrived 
SOCKADDR_IN   m_saHostGroup; //   SOCKADDR   structure   to   hold   IP/Port   of   the   Host   group   to   send   data   to   it 
ip_mreq   m_mrMReq; //   Contains   IP   and   interface   of   the   host   group 
UINT   m_nSendersPort; //   Holds   Port   No.   of   the   socket   from   which   last   packet   was   received 
CString   m_strSendersIP; //   Hold   IP   of   the   socket   from   which   the   last   packet   was   received 
UINT   m_nLocalPort; //   Ephemeral   port   number   of   the   sending   port 
CString   m_strLocalIP; //   IP   Address   of   the   local   host   or   your   machine 
BOOL   bForceNoLoopback; //   If   interface   does   not   support   lopback   and   the   service   is   required,   the   bool   is   set   to   true 

BOOL   bDataReceived; 
BOOL   LeaveGroup(); 
//BOOL   Send(const   void*,   int); 
BOOL   Send(csock_data   m_data1); 
BOOL   CreateSocket(LPCTSTR,   UINT); 
BOOL   ready[40]; 
int   number; 
CString   text; 

 
csock_data   msg_commanddata; 

BOOL   newfile; 
DWORD   fileID; 
DWORD     receivenumber; 
CString   filename; 

BOOL   GetMaker(void); 
void   SetMaker(BOOL   da); 
void   ReadFrom(void); 
void   Init(void); 
BOOL   TextSend(CString   text); 

BOOL   SendFile(CString   filename); 
void   ReadFile(void); 
BOOL   SendData(SOCKET_STREAM_FILE_INFO   m_data1); 


/ 
 
HINSTANCE   glib; 
LYKGETDATA   lykgetdata1; 
LYKSETDATA   lyksetdata1; 


//   Operations 
public: 
CMSGSocket(); 
virtual   ~CMSGSocket(); 

//   Overrides 
public: 
//   ClassWizard   generated   virtual   function   overrides 
//{{AFX_VIRTUAL(CMSGSocket) 
public: 
virtual   void   OnReceive(int   nErrorCode); 
//}}AFX_VIRTUAL 

//   Generated   message   map   functions 
//{{AFX_MSG(CMSGSocket) 
//   NOTE   -   the   ClassWizard   will   add   and   remove   member   functions   here. 
//}}AFX_MSG 

//   Implementation 
protected: 
}; 

/ 

//{{AFX_INSERT_LOCATION}} 
//   Microsoft   Visual   C++   will   insert   additional   declarations   immediately   before   the   previous   line. 

#endif   //   !defined(AFX_MSGSocket_H__257F140C_C139_4112_BACA_2C16C0F155B8__INCLUDED_) 


用法是: 

void   CMainFrame::SendMSG(int   pcommand,int   pmsg) 
{ 
if(!MSG_Socket.CreateSocket( "234.5.6.7 ",   206)) 
AfxMessageBox( "建立网络连接出错! "); 

//AfxMessageBox( "SendMSG "); 
//return; 
//AfxMessageBox( "aa "); 
::memset(&msg_commanddata,0,sizeof(csock_data)); 
msg_commanddata.command=pcommand; 
msg_commanddata.serial=pmsg; 
POINT   pt; 
GetCursorPos(&pt); 
msg_commanddata.mousex=pt.x; 
msg_commanddata.mousey=pt.y; 
// 
char   ch[128]; 
        ::gethostname(ch,100); 
hostent*   tent=::gethostbyname(ch); 
msg_commanddata.IP[0][0]=(byte)tent-> h_addr[0]; 
msg_commanddata.IP[0][1]=(byte)tent-> h_addr[1]; 
msg_commanddata.IP[0][2]=(byte)tent-> h_addr[2]; 
msg_commanddata.IP[0][3]=(byte)tent-> h_addr[3]; 

/// 
if(!MSG_Socket.Send(msg_commanddata)) 
{ 
// 
for(int   i=0;i <3;i++) 
{ 
//Sleep(100); 
if(!MSG_Socket.Send(msg_commanddata)) 
{ 
//AfxMessageBox( "send   data   failed "); 
                        //return; 
} 
else 
{ 
                                  //AfxMessageBox( "send   data   failed "); 
} 
} 
} 
else 
{ 
} 
//AfxMessageBox( "send   end "); 
//return; 
} 


 

 

//发送端程序



#include <stdio.h>
#include <winsock.h>



int main(int argc, char* argv[])
{
    WSADATA wsaData;          //指向WinSocket信息结构的指针
    SOCKET sockListener;
    SOCKADDR_IN sin,saUdpServ;
    BOOL fBroadcast = TRUE;
    char sendBuff[1024];
    int nSize;
    int ncount=0;
 // 初始化winsock库,使用socket的前提
    if(WSAStartup(MAKEWORD( 1, 1 ), &wsaData )!=0)//进行WinSocket的初始化
    {
        printf("Can't initiates windows socket!Program stop.\n");//初始化失败返回-1
        return -1;
    }
 // 创建socket
    sockListener=socket(PF_INET,SOCK_DGRAM,0);
 // 打开广播选项,是socket可以广播消息
    setsockopt ( sockListener,SOL_SOCKET,SO_BROADCAST, (CHAR *)&fBroadcast,sizeof ( BOOL ));
 // 将socket绑定到本地端口
    sin.sin_family = AF_INET;
    sin.sin_port = htons(0);
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind( sockListener, (SOCKADDR *)&sin, sizeof(sin))!=0)
    {
        printf("Can't bind socket to local port!Program stop.\n");//初始化失败返回-1
        return -1;
    }
 // 设定广播的目的端口
    saUdpServ.sin_family = AF_INET;
    saUdpServ.sin_addr.s_addr = htonl ( INADDR_BROADCAST );
    saUdpServ.sin_port = htons (7001);//发送用的端口,可以根据需要更改
    nSize = sizeof ( SOCKADDR_IN );
    while(1)
    {
  // 广播消息
        sprintf(sendBuff,"Message %d",ncount++);
        sendto ( sockListener,sendBuff,
            lstrlen (sendBuff),
            0,
            (SOCKADDR *) &saUdpServ,
            sizeof ( SOCKADDR_IN ));
        printf("%s\n",sendBuff);
    }
 return 0;
}


//接收
#include <stdio.h>
#include <winsock.h>
#include <conio.h>

int main(int argc, char* argv[])
{
    WSADATA wsaData;          //指向WinSocket信息结构的指针
    SOCKET sockListener;
    SOCKADDR_IN sin,saClient;
    char cRecvBuff[1024];
    int nSize,nbSize;
    int iAddrLen=sizeof(saClient);
    if(WSAStartup(MAKEWORD( 1, 1 ), &wsaData )!=0)//进行WinSocket的初始化
    {
        printf("Can't initiates windows socket!Program stop.\n");//初始化失败返回-1
        return -1;
    }
 // 绑定到7001端口,以监听来自网络的数据
    sockListener=socket(AF_INET, SOCK_DGRAM,0);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(7001);//发送端使用的发送端口,可以根据需要更改
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind( sockListener, (SOCKADDR FAR *)&sin, sizeof(sin))!=0)
    {
        printf("Can't bind socket to local port!Program stop.\n");//初始化失败返回-1
        return -1;
    }
    while(1)
    {
        nSize = sizeof ( SOCKADDR_IN );
  // 接受消息
        if((nbSize=recvfrom (sockListener,cRecvBuff,1024,0,(SOCKADDR FAR *) &saClient,&nSize))==SOCKET_ERROR)
        {
            printf("Recive Error");
            break;
        }
        cRecvBuff[nbSize] = '\0';
        printf("%s\n",cRecvBuff);
  
  
  
    }
    return 0;
}

广播

广播是指在一个局域网中向所有的网上节点发送信息。这是UDP连接的一种

广播有一个广播组,即只有一个广播组内的节点才能收到发往这个广播组的信息。什么决定了一个广播组呢,就是端口号,局域网内一个节点,如果设置了广播属性并监听了端口号A后,那么他就加入了A组广播,这个局域网内所有发往广播端口A的信息他都收的到。在广播的实现中,如果一个节点想接受A组广播信息,那么就要先将他绑定给地址和端口A,然后设置这个socket的属性为广播属性。如果一个节点不想接受广播信息,而只想发送广播信息,那么不用绑定端口,只需要先为socket设置广播属性后,向广播地址INADDR_BROADCAST的A端口发送udp信息即可。详细的程序实现如下:

1.初始化

    WSAStartup(MAKEWORD(2,2),&wsad);

2.创建一个UDP的socket
    s=socket(AF_INET,SOCK_DGRAM,0);

3.如果这个socket希望收到信息,则需要绑定地址和这组广播的端口号,如果只是希望发送广播信息,则不需要这步

    SOCKADDR_IN udpAdress,sender;
    int senferAddSize=sizeof(sender);
    udpAdress.sin_family=AF_INET;
    udpAdress.sin_port=htons(11114);
    udpAdress.sin_addr.s_addr=inet_addr("10.11.131.32");
    bind(s,(SOCKADDR*)&udpAdress,sizeof(udpAdress));

//这样这个节点即可收到局域网内所有发往端口11114的广播信息

4.设置socket的属性为广播
    bool optval=true;
    setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char*)&optval,sizeof(bool));

5.下面就可以使用recvfrom或sendto来收发广播信息了

这里是接受,这是一个阻塞操作
            ret=recvfrom(s,data,1000,0,(SOCKADDR*)&sender,&senferAddSize);

这里是像该广播组发送信息,注意发送的地址为广播地址INADDR_BROADCAST,端口号为改组广播的端口号11114

    SOCKADDR_IN dstAdd;
    dstAdd.sin_family=AF_INET;
    dstAdd.sin_port=htons(11114);
    dstAdd.sin_addr.s_addr=INADDR_BROADCAST;
    sendto(s,data(),totalbyte,0,(SOCKADDR*)&dstAdd,sizeof(SOCKADDR));

多播

多播与广播不同,多播是指一条信息向局域网内有限几个节点传递,而广播是不管某个节点是否在制定组内,都会向这个节点发送广播信息,容易造成网络负担严重。

多播的实现是靠多播组,在局域网内,一个多播地址唯一的定义了一个多播组(端口号任意),可以使用的多播地址是有规定的,从224.0.0.0—239.255.255.255之间,但是其中的一些地址不能用,是用作特殊用途的:224.0.0.0 –224.0.0.2  224.0.1.1  224.0.0.9 224.0.1.24。一个节点如果想接受自某个多播组或向某个多播组发送信息,必须首先加入多播组,然后给予UDP发送。下面是详细的代码实现。

1.初始化

    WSAStartup(MAKEWORD(2,2),&wsad);

2.这里传建一个用于多播通信的socket,注意这个socket的参数为设置成多播
    s=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|WSA_FLAG_OVERLAPPED);

3.将socket绑定到一个本地地址、端口,和广播不同,在多播中,无论是发送还是接收端都必须绑定一个本地地址,这个地址就是多播通信时处理信息的端口
    udpAdress.sin_family=AF_INET;
    udpAdress.sin_port=htons(22222);
    udpAdress.sin_addr.s_addr=inet_addr("10.11.131.32");
    bind(s,(SOCKADDR*)&udpAdress,sizeof(udpAdress));

4.定义多播组的地址
    multiCastGroup.sin_family=AF_INET;
    multiCastGroup.sin_port=htons(1111);此处端口任意,每个节点的可以设置成不同的
    multiCastGroup.sin_addr.s_addr=inet_addr("224.0.0.3"); 此处需使用上面规定地址段内的多播地址

5.加入这个多播组。注意这里的函数返回了一个socket,这个socket不负责通信,只是在脱离多播组时使用

    SOCKET sockM=WSAJoinLeaf(s,(SOCKADDR*)&multiCastGroup,sizeof(multiCastGroup),NULL,NULL,NULL,NULL,JL_BOTH);

6.下面使用recvfrom接受多播信息,或者使用sendto发送多播信息  

ret=recvfrom(s,data,1000,0,(SOCKADDR*)&sender,&senferAddSize);

sendto(s,data(),totalbyte,0,(SOCKADDR*)&multiCastGroup,sizeof(multiCastGroup));

7.最后关闭清理
    closesocket(sockM);
    closesocket(s);
    WSACleanup();

其他:

1)在多播组中,默认情况下一个发出多播信息的节点也会收到自己发送的信息,这称为多播回环,可以关闭多播回环:

bool val=false;

setsocket(s,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)val,sizeof(val));

2)在多播时,通常要设置适当的TTL(TTL的值是多少,那么多播信息就可以经过多少路由器,每经过一个路由器,TTl的值自动减1):

int val=3;

setsocket(s,IPPROTO_IP,IP_MULTICAST_TTL,(char*)val,sizeof(int));

 

	//
	// UDPServer.cpp 
#include <stdio.h>
#include <WINSOCK2.H> 
#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE    64 
	int main(void)
	{    
		WSADATA wsd;    
		SOCKET  s;    
		int     nRet;     
		// 初始化套接字动态库    
		if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)    
		{        
			printf("WSAStartup failed !\n");        
			return 1;    
		}     
		// 创建套接字    
		s = socket(AF_INET,SOCK_DGRAM,0);    
		if(s == INVALID_SOCKET)    
		{        
			printf("socket() failed ,Error Code:%d\n",WSAGetLastError());        
			WSACleanup();        
			return 1;    
		}     
		SOCKET      socketSrv = socket(AF_INET,SOCK_DGRAM,0);    
		SOCKADDR_IN addrSrv;    
		SOCKADDR_IN addrClient;    
		char        buf[BUF_SIZE];    
		int         len = sizeof(SOCKADDR);     
		// 设置服务器地址    
		ZeroMemory(buf,BUF_SIZE);    
		addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);    
		addrSrv.sin_family = AF_INET;    
		addrSrv.sin_port = htons(5000);     
		// 绑定套接字    
		nRet = bind(socketSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));    
		if(SOCKET_ERROR == nRet)       
		{           
			printf("bind failed !\n");           
			closesocket(s);           
			WSACleanup();           
			return -1;       
		}    
		// 从客户端接收数据    
		nRet = recvfrom(socketSrv,buf,BUF_SIZE,0,(SOCKADDR*)&addrClient,&len);    
		if(SOCKET_ERROR == nRet)       
		{           
			printf("recvfrom failed !\n");           
			closesocket(s);           
			WSACleanup();           
			return -1;       
		}    
		// 打印来自客户端发送来的数据    
		printf("Recv From Client:%s\n",buf);     
		// 向客户端发送数据    
		sendto(socketSrv,"UDP Hello World !",sizeof("UDP Hello World !"),0,(SOCKADDR*)&addrClient,len);    
		closesocket(s);    
		WSACleanup();    
		return 0;
	}


 

	//
	// UDPClient.cpp 
#include <stdio.h>
#include <WINSOCK2.H> 
#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE    64 
	int main(void)
	{    
		WSADATA wsd;        
		SOCKET  s;     
		// 初始化套接字动态库    
		if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)    
		{        
			printf("WSAStartup failed !\n");        
			return 1;    
		}     
		// 创建套接字    
		s = socket(AF_INET,SOCK_DGRAM,0);    
		if(s == INVALID_SOCKET)    
		{        
			printf("socket() failed, Error Code:%d\n",WSAGetLastError());        
			WSACleanup();        
			return 1;    
		}     
		char        buf[BUF_SIZE];  
		// 接受数据    
		SOCKADDR_IN servAddr;       
		// 服务器套接字地址    
		SOCKET      sockClient = socket(AF_INET,SOCK_DGRAM,0);    
		int         nRet;     ZeroMemory(buf,BUF_SIZE);    
		strcpy(buf,"UDP Hello World !");     
		// 设置服务器地址    
		servAddr.sin_family = AF_INET;    
		servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.254");    
		servAddr.sin_port = htons(5000);     
		// 向服务器发送数据    
		int nServAddLen = sizeof(servAddr);    
		if(sendto(sockClient,buf,BUF_SIZE,0,(sockaddr *)&servAddr,nServAddLen) == SOCKET_ERROR)    
		{        
			printf("recvfrom() failed:%d\n",WSAGetLastError());        
			closesocket(s);        
			WSACleanup();        
			return 1;    
		}    
		nRet = recvfrom(sockClient,buf,BUF_SIZE,0,(sockaddr *)&servAddr,&nServAddLen);    
		if(SOCKET_ERROR == nRet)       
		{           
			printf("recvfrom failed !\n");           
			closesocket(s);           
			WSACleanup();           
			return -1;       
		}     
		// 打印来自服务端发送来的数据    
		printf("Recv From Server:%s\n",buf);    
		closesocket(s);    
		WSACleanup();    
		return 0;
	}


 

 本文讲述了SOCKADDR 与 SOCKADDR_IN 的区别与联系。已经里面涉及的结构体 联合体 等的一些细节问题。这个是一个很基础的问题,但是很多人都是似是而非的理解着!下面详解了这个谜团!

-----------------------------------------------------------------------------------------------------------------------

struct sockaddr {
        unsigned short sa_family; //    地址族, AF_xxx               AF_INET 不涉及转序的问题
        char sa_data[14];    // 14字节的协议地址 网络字节顺序的
    };
  
上面是通用的socket地址,共16个字节!

具体到Internet socket,用下面的结构,二者可以进行类型转换
  
struct sockaddr_in {
        short int sin_family; /* 地址族 */
        unsigned short int sin_port; /* 端口号 */
       struct in_addr sin_addr; /* Internet地址 */
        unsigned char sin_zero[8]; /* 与struct sockaddr一样的长度 */ 16个字节
    };
  
    ---------------------------struct in_addr 就是32位IP地址---------------------------------
第一种表示方式:  
    struct in_addr {
        unsigned long s_addr;
    };

第二种表示方式:
struct in_addr

   union
{   
     struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;   
     struct { u_short s_w1,s_w2;} S_un_w;   
     u_long S_addr;
} S_un;
};

利用u_long htonl(u_long hostlong);将主机字节序转换为TCP/IP网络字节序.
利用u_short htons(u_short hostshort);将主机字节序转换为TCP/IP网络字节序.

inet_addr()是将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001)。

通常的用法是:
SOCKET sockfd;
struct sockaddr_in my_addr;   //SOCKETADDR_IN my_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 做一些错误检查! */

my_addr.sin_family = AF_INET; /* 主机字节序 */
my_addr.sin_port = htons(MYPORT); /* short, 网络字节序 */

//有两种方式 对应上面 in_addr 的两种方式
my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");
//my_addr.sin_addr.S_un.s_addr = inet_addr("192.168.0.1");

bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
/* 不要忘了为bind()做错误检查: */
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

 

 

 


 

 

 

    

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值