服务器和客户机采用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))
- {
- 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))
- 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
- #include
- 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
- #include
- #include
- 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.9224.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
- #include
- #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
- #include
- #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));