1. 程式人生 > >用Socket在區域網內進行廣播

用Socket在區域網內進行廣播

伺服器和客戶機採用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));

相關推薦

Socket區域網進行廣播

伺服器和客戶機採用Socket程式設計。 問題1:伺服器進入偵聽狀態,但是此時客戶端並不知道伺服器的地址。我該如何做? 問題2:我想使客戶端先發出一個廣播,伺服器接受廣播後給客戶機發送自己的Ip等資訊。 接著再建立Socket通訊。這樣對嗎? 問題3:是不是進行廣播

Linux、window伺服器下建立共享資料夾(方便與區域網進行檔案共享)

SEO關鍵字:samba伺服器的搭建 ServU的安裝使用 玉念聿輝 Linux共享檔案 window共享檔案 深圳市奧捷迅科技 吳明輝 感謝CSDN品臺。 Linux下samba的安裝和建立共享檔案 1、關閉selinux setenforce 0 2、關閉ipta

不同區域網進行網路連線的建立方法

前言 在這網際網路和物聯網的時代,網路連線與通訊被使用的越來越多,如何建立兩個網路IP地址的連線 (TCP或者UDP連線),也是一門學問。之前專案中遇到了這方面的問題,也被糾纏了一番,查閱大量資料,通過不斷摸索和學習,對網路通訊有了一定的理解,下面以個人的理解

python 獲取區域網廣播地址

#-*- coding:utf-8 -*- import subprocess import re import socket def getBroadAddList(): ######獲取IP以及子網掩碼 #######windows 下的命令是ipcon

Python Socket網路程式設計(二)區域網區域網與廣域網的持續通訊

目錄 前言 IP地址 簡介 公有IP 私有IP 區域網之間網路通訊 前提 功能描述

pythontcp實現區域網檔案傳輸(文字,圖片,視訊)

功能: 可以利用python建立的TCP客戶端從我們自己搭建的TCP伺服器上下載檔案. 實現需求: 安裝socket模組 簡單瞭解sokcet模組用法 伺服器程式碼如下: import socket def file_deal(file_name):     # 定義

如何把區域網不同資料庫的兩個表的資料進行傳輸?

應用場景:當測試資料庫的資料不小心被清空了,需要從別的庫裡把資料恢復過來;或者測試庫增加了某表的一些資料,正式庫需要同時更新(當然穩妥的是儲存更新語句)等等,這時就需要用到這個小技巧了。 第一句是把b表中的選單表的資料放到當前資料庫中,並且新建一張tmenu表: select * into TMENU f

ZeroMQ例項-使用ZMQ(ZeroMQ)進行區域網網路通訊

本文內容摘要:1)安裝zeromq、2)例項說明使用zmq進行網路間的訊息傳送和接收 首先在機器中安裝zmq庫 步驟如下: 1)下載zeromq的原始碼,ZeroMQ的官方網址:         注:在本文寫作時,ZMQ版本已經升級到4.1.0,不過影響沒多大 2)解壓原始檔 tar

區域網主機之間Socket通訊實現

只能傳輸文字且只能在區域網內實現通訊 主機1: package SocketTest; import java.net.*; import java.io.*; import java.awt.*; import javax.swing.*; import java.u

【C#】-區域網Socket實現通訊

前言 聽起區域網下聊天是不是很難,很高大上的樣子,怎麼樣讓兩臺電腦,在同一區域網下實現聊天呢,先說一下思路吧,一會直接上程式碼。 1. 首先我們先要建立一個伺服器,也就是說兩臺電腦有一臺要當著伺服器,供客戶端連結。 2.

Socket做一個區域網聊天工具

程式設計成為簡單的服務端和客戶端之間的通訊, 但通過一些方法可以將這兩者進行統一起來, 讓服務端也成為客戶端, 讓客戶端也成為服務端, 使它們之間可以互相隨時不間斷的通訊. 考慮到實現最原始的服務端和客戶端之間的通訊所需要的步驟對於寫這樣的程式是很有幫助的.   作為服務端,

使用arp欺騙進行同一區域網的抓包

環境 作業系統: MacOS 10.13.4 包管理工具:MacPorts 2.4.4 arp欺騙工具:arpspoof 2.4 抓取區域網內的IP地址的工具:nmap 7.70 抓包工具:Wireshark 2.4.3 前言 本來是想了解如何

Socket實現服務端和客戶端,進行一對一順序對話

一、服務端程式碼 import java.net.ServerSocket; import java.net.Socket; import java.io.IOException; import java.io.InputStream; import ja

【技巧】手機訪問區域網Apache網站

寫在前面 之前不知道還有這麼一個技巧,以前手機真機測試webApp都是開電腦的WiFi,然後在手機裡開啟代理來訪問這個網站。這樣對裝置的依賴性比較大,試想哪天沒帶膝上型電腦,或者在沒有WiFi發射器的桌上型電腦裡怎麼用這個方式? Apache配置修改

區域網IIS架設網站,解決本機可訪問,但網其他使用者無法訪問問題

在Window7作業系統中安裝配置好IIS後,本地釋出測試網站程式沒有問題,但是區域網等遠端使用者不能正常訪問網站程式,提示“Internet Explorer 無法顯示該網頁”。本地可以正常訪問IIS但是遠端不能訪問

有1000瓶藥水,其中只有一瓶有毒。現在小白鼠進行實驗,小白鼠只要服用任意量有毒藥水就會在24小時死亡。問至少要多少隻小白鼠進行實驗才能檢測出哪瓶藥水有毒?

時間不是問題,24小時內肯定可以找出有毒的那瓶。  給1000個瓶分別標上如下標籤(10位長度):  0000000001 (第1瓶)  0000000010 (第2瓶)  0000000011 (第3瓶)  ......  1111101000 (第1000瓶)  從編號

【MySQL比知必會】第八章 通配符進行過濾

通配符 操作符 範圍 name 使用 技巧 商品 -- rom 1、LIKE操作符   之前使用的操作符都是針對已知的數據,而使用通配符可以對未知數據也進行搜索。   通配符(wildcard):用來匹配值得一部分的特殊字符。   搜索模式(search pattern):

字符設備驅動ioctl實現戶層核層通信

default eof 建設 code gcc app std size smo 測試代碼實現 memdev.h #ifndef _MEMDEV_H_ #define _MEMDEV_H_ #include<linux/ioctl.h> #ifndef MEM

XMLRPC開服務進行server/client通信

elif 工具 註意事項 tar ann popu cannot family put 本文講一下怎樣用python的xmlrpc開服務,進行server/client的通信。應用場景:1)需多client訪問應用程序給予應答情況——網頁服務。 2)數據極大,希望載入一

使用python3.x實現統計Nginx進程所占的物理

linux 進程 統計 python nginx 實現代碼如下:#!/usr/bin/python #coding:utf8 from subprocess import Popen, PIPE import os nginxpid = Popen(["pidof", "nginx"]