IP地址的簡介:
IP地址是由32位二進位組成:網路號+主機號。同一個物理網路上的所有主機都使用同一個網路ID,網路上的一個主機(包括網路上工作站,伺服器和路由器等)有一個主機ID與其對應。IP地址分為A、B、C、D、E5類。常用的是B和C兩類。
一個A類IP地址是指, 在IP地址的四段號碼中,第一段號碼為網路編號,剩下的三段號碼為本機電腦的號碼。如果用二進位表示IP地址的話,A類IP地址就由1位元組的網路地址和3位元組主機地址組成,網路地址的最高位必須是“0”。
一個B類IP地址是指,在IP地址的四段號碼中,前兩段號碼為網路編號。如果用二進位表示IP地址的話,B類IP地址就由2位元組的網路地址和2位元組主機地址組成,網路地址的最高位必須是“10”。
一個C類IP地址是指,在IP地址的四段號碼中,前三段號碼為網路編號,剩下的一段號碼為本機電腦的號碼。如果用二進位表示IP地址的話,C類IP地址就由3位元組的網路地址和1位元組主機地址組成,網路地址的最高位必須是“110”。
C類IP地址的子網路遮罩為255.255.255.0,每個網路支援的最大主機數為256-2=254台
D類IP地址:1110 +多播地址
即多播位址範圍: 224.0.0.1 - 239.255.255.255
全0或全1的網路號、主機號保留作特殊用途:
網路號
|
主機號
|
代表的意思
|
全0
|
全0
|
本網路上本主機
|
全0
|
host-id
|
本網路上主機號為host-id的主機
|
net-id
|
全1 |
不分配給任何主機,表示某個網路的網路地址,代表的是一個網段 |
| 全1 |
全1
|
表示本網路上所有的主機,是本網的廣播位址
|
net-id
|
全1
|
對net-id網路上所有主機進行廣播,是遠程網路的廣播位址
|
/*********************************************************************** Compiler: GCC* Last Update: Sat 12 Nov 2011 11:52:25 PM CST* File Name: myServerUDP1.c* Description: UDP點對點通訊伺服器端,預設連接埠地址為PORT* Usage: ./mySErverUDP1 伺服器所綁定的IP地址 連接埠號碼************************************************************************/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#define MAXBUF 1024#define PORT 60000 int main(int argc, char **argv){ int myFd, clientFd; struct sockaddr_in myAddr, clientAddr; int addrlen = sizeof(clientAddr); char buf[MAXBUF]; char addrTemp[INET_ADDRSTRLEN]; bzero(&myAddr, sizeof(myAddr)); bzero(&clientAddr, sizeof(clientAddr)); //建立通訊端,datagrams if((myFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { printf("錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } myAddr.sin_family = AF_INET; if (argc == 2) { //IP地址 int res; if ((res = inet_pton(AF_INET, argv[1], &myAddr.sin_addr)) == -1) { printf("錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } else if(res == 0) { printf("IP地址無效\n"); return 0; } } else { myAddr.sin_addr.s_addr = INADDR_ANY; } if (argc == 3) { myAddr.sin_port = htons(atoi(argv[2])); } else { myAddr.sin_port = htons(PORT); } if(bind(myFd, (struct sockaddr *)&myAddr, sizeof(myAddr)) != 0) { printf("錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } printf("伺服器已啟動,等待串連中.....\n"); while (1) { bzero(buf, sizeof(buf)); if (recvfrom(myFd, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&clientAddr, &addrlen) == -1) { printf("錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } printf("收到來自%s的訊息:%s\n", inet_ntop(AF_INET, &clientAddr.sin_addr, addrTemp, sizeof(addrTemp)), buf); } return 0;}
/*********************************************************************** Compiler: GCC* Last Update: Sat 12 Nov 2011 11:39:22 PM CST* File Name: myClientUDP1.c* Description: UDP點對點或廣播通訊用戶端,連接埠號碼預設為PORT* Usage: ./myClientUDP1 對方IP地址 連接埠號碼************************************************************************/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#define MAXBUF 1024#define PORT 60000 int main(int argc, char **argv){ int myFd; struct sockaddr_in serverAddr; int addrlen = sizeof(serverAddr); char buf[MAXBUF]; bzero(&serverAddr, sizeof(serverAddr)); bzero(buf, sizeof(buf)); //建立通訊端,datagrams if((myFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { printf("socket()錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } /* 設定通訊方式對廣播,即本程式發送的一個訊息,網路上所有主機均可以收到 */ int yes = 1; if(setsockopt(myFd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) != 0) { printf("setsockopt()錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } //設定對方的IP地址和連接埠等屬性; serverAddr.sin_family = AF_INET; if (argc > 1) { //IP地址 int res; if ((res = inet_pton(AF_INET, argv[1], &serverAddr.sin_addr)) == -1) { printf("inet_pton()錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } else if(res == 0) { printf("IP地址無效\n"); return 0; } } else { printf("Usage: %s 對方IP地址\n", argv[0]); return 0; } if (argc == 3) { serverAddr.sin_port = htons(atoi(argv[2])); } else { serverAddr.sin_port = htons(PORT); } strcpy(buf, "Hello,I'm Client"); if (sendto(myFd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) { printf("sendto()錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } printf("成功給伺服器發送訊息:\"%s\"\n", buf); return 0;}
Windows下的一個UDP伺服器程式
#include <stdio.h>#include <Winsock2.h>#define LISTEN_PORT 8888int main(){ SOCKET socket1; WSADATA wsaData; int iErrorCode; if (WSAStartup(MAKEWORD(2,1),&wsaData)) //調用Windows Sockets DLL { printf("Winsock無法初始化!\n"); WSACleanup(); return 1; } printf("伺服器開始建立SOCKET。\n"); struct sockaddr_in local; struct sockaddr_in from; int fromlen =sizeof(from); local.sin_family=AF_INET; local.sin_port=htons(LISTEN_PORT); ///監聽連接埠 local.sin_addr.s_addr=INADDR_ANY; ///本機 socket1=socket(AF_INET,SOCK_DGRAM,0); bind(socket1,(struct sockaddr*)&local,sizeof(local)); while (1) { char buffer[1024]="\0"; printf("waiting for message from others-------------\n"); if (recvfrom(socket1,buffer,sizeof(buffer),0,(struct sockaddr*) &from,&fromlen)!=SOCKET_ERROR) { printf("Received datagram from %s--%s\n",inet_ntoa(from.sin_addr),buffer); ////給cilent發資訊 sendto(socket1,buffer,sizeof(buffer),0,(struct sockaddr*)&from,fromlen); } //Sleep(1000); } closesocket(socket1); return 0;}
如果不設定通訊方式為廣播方式的話,進行廣播會出現
[test1@localhost 周立發]$ ./myClientUDP1 192.168.1.255
sendto()錯誤碼:13, Permission denied
設定通訊方式為廣播方式,進行測試,可以去下載一個 TCP&UDP_SocketTest調試工具v2.2,在windows下開啟一個伺服器,或者在主機windows下也寫一個UDP伺服器程式,要是通過無線上網的話,主機沒法收到虛擬機器的廣播訊息,不知道怎麼回事,通過無線上網就行。
以下是測試過程,windows下
[test1@localhost 周立發]$ ./myClientUDP1 255.255.255.255
成功給伺服器發送訊息:"Hello,I'm Client"
[test1@localhost 周立發]$ ./myServerUDP1
伺服器已啟動,等待串連中.....
收到來自192.168.1.104的訊息:Hello,I'm Client
主機Win7測試程式的運行結果:
伺服器開始建立SOCKET。
aiting for message from others-------------
eceived datagram from 192.168.1.104--Hello,I'm Client
廣播成功!
************************************************************************
廣播的缺點:不管主機是否有程式接收廣播訊息,廣播訊息一定會被網卡收到並提交給作業系統去處理,所以會造成網路上流量增大,對不接收廣播訊息的主機造成一定的負擔。
像廣播一樣,多播訊息一樣會被複製發到網路所有主機的網卡上,但只有宣布加入某個多播組的主機的網卡才會把資料提交給作業系統去處理。如果沒有加入組,則網卡直接將資料丟棄。
************************************************************************
多點傳送伺服器端編程步驟:
1、調用socket()建立通訊端
2、設定一個多播的IP地址和連接埠
3、向此多播地址發送資料
多播用戶端編程步驟:
1、調用socket()建立通訊端
2、步聚2可選,設定本上迴環許可IP_MULTICAST_LOOP.預設該選項是啟用的。
3、步聚3可選,設定IP_MULTICAST_TTL,每經過一個路由器,TTl的值自動減1。該值預設為1,防止多播報文往區域網路外傳播,可對其進行設定(0~255)
4、首先對下面這個結構體賦值
struct ip_mreq
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
然後調用setsockopt將本機加入多播組
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(struct ip_mreq))
5、調用bind()綁定本地通訊端
6、recvfrom()
7、退出廣播組setsockopt (socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)
樣本程式:
/*********************************************************************** Compiler: GCC* Last Update: Sat 12 Nov 2011 11:33:01 PM CST* File Name: myServerMulticast2.c* Description: 多播用戶端* Usage: myServerMulticast2 多播地址 [連接埠號碼(預設為PORT)]************************************************************************/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#define MAXBUF 1024#define PORT 60000 int main(int argc, char **argv){ int myFd; struct sockaddr_in mCastAddr; int addrlen = sizeof(mCastAddr); char buf[MAXBUF]; bzero(&mCastAddr, sizeof(mCastAddr)); bzero(buf, sizeof(buf)); //建立通訊端 if((myFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { printf("socket()錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } mCastAddr.sin_family = AF_INET; if (argc > 1) { //IP地址 int res; if ((res = inet_pton(AF_INET, argv[1], &mCastAddr.sin_addr)) == -1) { printf("inet_pton()錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } else if(res == 0) { printf("IP地址無效\n"); printf("請輸入一個多播地址:224.0.0.1 ~ 239.255.255.255\n"); return 0; } } else { printf("Usage: %s 多播IP地址\n", argv[0]); return 0; } if (argc == 3) { mCastAddr.sin_port = htons(atoi(argv[2])); } else { mCastAddr.sin_port = htons(PORT); } //設定IP_MULTICAST_TTL 為1,即該多播最多隻能經過一個路由器.TTL預設即為1 //u_char ttl = 1; //if (setsockopt(myFd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) != 0) { // printf("%s Line number:%d setsockopt()錯誤碼:%d, %s\n", \ // __FILE__, __LINE__, errno, strerror(errno)); // exit(errno); //} while (1) { bzero(buf, sizeof(buf)); printf("請輸入要發送的訊息:"); if (fgets(buf, sizeof(buf), stdin) == NULL) { exit(0); } if (sendto(myFd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&mCastAddr, sizeof(mCastAddr)) == -1) { printf("sendto()錯誤碼:%d, %s\n", errno, strerror(errno)); exit(errno); } printf("成功給對方發送訊息:%s", buf); } return 0;}
/*********************************************************************** Compiler: GCC* Last Update: Sat 12 Nov 2011 11:17:13 PM CST* File Name: myClientMulticast2.c* Description: ************************************************************************/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netinet/in.h>#include <sys/types.h>#include <sys/socket.h>#define _DEBUG#define MAXBUF 1024#define PORT 60000 int main(int argc, char **argv){ int myFd, clientFd; struct sockaddr_in myAddr, clientAddr; struct ip_mreq mreq; int addrlen = sizeof(clientAddr); char buf[MAXBUF]; char addrTemp[INET_ADDRSTRLEN]; bzero(&myAddr, sizeof(myAddr)); bzero(&clientAddr, sizeof(clientAddr)); //建立通訊端,datagrams if((myFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { printf("%s Line number:%d socket()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } //設定本地地址連接埠資訊 myAddr.sin_family = AF_INET; myAddr.sin_addr.s_addr = INADDR_ANY; if (argc == 3) { myAddr.sin_port = htons(atoi(argv[2])); } else { myAddr.sin_port = htons(PORT); } //綁定本地通訊端 if(bind(myFd, (struct sockaddr *)&myAddr, sizeof(myAddr)) != 0) { printf("%s Line number:%d bind()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } //設定IP_MULTICAST_LOOP u_char loop = 1; if (setsockopt(myFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != 0) { printf("%s Line number:%d setsockopt()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } //設定IP_MULTICAST_TTL 為1,即該多播最多隻能經過一個路由器 u_char ttl = 1; if (setsockopt(myFd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) != 0) { printf("%s Line number:%d setsockopt()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } //對struct ip_mreq這個結構體賦值 if (argc > 1) { //設定IP地址 int res; if ((res = inet_pton(AF_INET, argv[1], &mreq.imr_multiaddr)) == -1) { printf("%s Line number:%d setsockopt()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } else if(res == 0) { printf("IP地址無效\n"); printf("請輸入一個多播地址:224.0.0.1 ~ 239.255.255.255\n"); return 0; } } else { printf("Usage:%s 多播地址(224.0.0.1 ~ 239.255.255.255)\n", argv[0]); return(0); } mreq.imr_interface.s_addr = INADDR_ANY; //將本機加入多播組中 if (setsockopt (myFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) { printf("%s Line number:%d setsockopt()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } printf("用戶端已啟動,等待多播訊息.....\n"); while (1) { bzero(buf, sizeof(buf)); if (recvfrom(myFd, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&clientAddr, &addrlen) == -1) { printf("%s Line number:%d recvfrom()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } printf("收到來自%s的訊息:%s", inet_ntop(AF_INET, &clientAddr.sin_addr, addrTemp, sizeof(addrTemp)), buf); if (strcmp("exit\n", buf) == 0) { break; } } //退出廣播組 if (setsockopt (myFd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) { printf("%s Line number:%d setsockopt()錯誤碼:%d, %s\n", \ __FILE__, __LINE__, errno, strerror(errno)); exit(errno); } return 0;}
同樣,必須在主機有線上網的情況下主機才能收到虛擬機器的多播訊息,主機通過無線上網收不到!這個問題有待解決。
運行結果:
起始我輸入一個非法的多播地址,結果出錯了
[test1@localhost 周立發]$ ./myClientMulticast2 244.0.0.88
setsockopt()錯誤碼:22, Invalid argument
//在試圖加到一個多播組裡出錯了
setsockopt (myFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)
#重新輸入一個正確的多播地址,如224.1.1.1
[test1@localhost 周立發]$ ./myServerMulticast2 224.1.1.1
請輸入要發送的訊息:hello
成功給對方發送訊息:hello
請輸入要發送的訊息:exit
成功給對方發送訊息:exit
[test1@localhost 周立發]$ ./myClientMulticast2 224.1.1.1
用戶端已啟動,等待多播訊息.....
收到來自192.168.1.104的訊息:hello
收到來自192.168.1.104的訊息:exit
主機windows下用TCP/UDP SOCKET調試工具V2.2 也成功收到多播資料。
23:45:05 收到資料:hello
23:45:08 收到資料:exit
@@@@@@
來源:http://book.51cto.com/art/200912/168573.htm