學習筆記,小白可以相互學習,大佬看到能告訴咱理解不對的地方就好了。
UDP服務器流程:
1.socket
2.bind
3.具體操作(write/read/recvfrom/sebdto)
UDP客戶端流程:
1.socket
2.bind(可選)
3.具體操作(write/read/recvfrom/sebdto)
/******client.c************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main()
{
int ret;
int sockfd;
char buf[256];
struct sockaddr_in srvaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
memset(&srvaddr, 0, sizeof(struct sockaddr_in));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(9999);
srvaddr.sin_addr.s_addr = inet_addr("192.168.2.100");
while(1) {
fgets(buf, sizeof(buf), stdin);
ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
if (ret == -1) {
perror("sendto");
return -1;
}
memset(buf, 0, sizeof(buf));
ret = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
if (ret == -1) {
perror("recvfrom");
return -1;
}
printf("buf : %s\n", buf);
}
return 0;
}
/*****server.c*************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main()
{
int ret;
int sockfd;
char buf[256];
struct sockaddr_in srvaddr;
struct sockaddr_in cltaddr;
socklen_t addrlen;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
memset(&srvaddr, 0, sizeof(struct sockaddr_in));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(9999);
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
if (ret == -1 ) {
perror("bind");
return -1;
}
while(1) {
memset(buf, 0, sizeof(buf));
addrlen = sizeof(struct sockaddr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&cltaddr, &addrlen);
if (ret == -1) {
perror("recvfrom");
return -1;
}
printf("buf : %s\n", buf);
sleep(10);
ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&cltaddr, addrlen);
if (ret == -1) {
perror("sendto");
return -1;
}
}
return 0;
}
網絡信息檢索函數:
1.gethostname()獲得主機名
2.getpeername()獲得與套接口相連的遠程協議地址
3.getsockname()獲得本地套接口協議地址
4.gethostbyname()根據主機名取得主機信息
5.gethostbyaddr()根據主機地址取得主機信息
6.getprotobyname()根據協議名取得主機協議信息
7.getprotrbynumber()根據協議號取得主機協議信息
8.getserverbyname()根據服務名取得相關服務信息
9.getserverbyport()根據端口號取得相關服務信息
10.getsockopt()/setsockopt()獲取/設置一個套接口選項
11.ioctl()/fcntl()設置套接口工作方式
網絡超時檢測
1.設置socket的屬性SO_RCVTIMEO
參考代碼:
struct tumeval tv;
tv.tv_sec = 5;//設置5秒時間,單位s
tv.t._usec = 0;//設置時間0ms,單位ms
setsockopt(sockfd,SOL_RCVTINMEO,&tv,sizeof(tv));//設置接收超時
recv()/recvfrom()/write()/read;//具體操作...,從socket讀取或者接收數據
2.用select檢測socket是否‘ready’
參考代碼:
struct fd_set radfs;
struct timeval tv = {5,0};//設置5秒時間
FD_ZERO(&rdfs);
FD_SET(sockfd,&rdfs);
if(select(sockfd+1,&rdfs,NULL,NULL,&tv) > 0)//socket就緒
{
recv()/recvfrom()/write()/read;//具體操作...,從socket讀取或者接收數據
}
3.設置定時器(timer),捕捉SIGALRM信號
參考代碼:
void handler()int signo {return ;}//一旦進程收到這個信號,執行完信號處理函數之後,下一個函數就會直接返回,不阻塞在哪裏
struct sigaction act;
sigaction(SIGALRM.NULL,&act);
act.sa_handler = handler;
act.sa_flags &= ~SA_RESTART;
sigaction(SIGALRM,&act,NULL);
alarm(5);
if(recv(...) < 0).....
廣播(broadcast)
前面介紹的數據包發送方式只有一個接受方,稱爲單播。
如果同時發給局域網中的所有主機,稱爲廣播。
只有用戶數據報(使用UDP協議)套接字才能廣播。
int setsockopt(int sockfd,int level,i
nt optname,const void *optval,socklen_t optelen)
level:指定控制套接字的層次可以取三種值:
1.SOL_SOCKET通用套接字選項 2.IPPROTO_IP: ip選項 3.IPPROTO_TCP: tcp選項
optname:存放選項值的緩衝區首地址
optlen:緩衝區首地址
optval:獲得或者設置套接字選項,根據選項名稱的數據類型進行轉換。
返回值:成功:0,失敗:-1,並設置errno
廣播發送:
1.創建用戶數據報套接字
2.缺省創建的套接字不允許廣播數據包,需要設置屬性(setsockopt可以設置套接字屬性)
3.接收方地址指定爲廣播地址(a.指定端口信息 b.發送數據包)
廣播接收:
1.創建用戶數據報套接字
2.綁定IP地址(廣播IP或者0.0.0.0)和端口
3.等待接收數據
/*******server.c************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main()
{
int ret;
int sockfd;
char buf[256];
struct sockaddr_in srvaddr;
struct sockaddr_in cltaddr;
socklen_t addrlen;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
memset(&srvaddr, 0, sizeof(struct sockaddr_in));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(9999);
srvaddr.sin_addr.s_addr = inet_addr("192.168.2.255");
ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
if (ret == -1 ) {
perror("bind");
return -1;
}
while(1) {
memset(buf, 0, sizeof(buf));
addrlen = sizeof(struct sockaddr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&cltaddr, &addrlen);
if (ret == -1) {
perror("recvfrom");
return -1;
}
printf("buf : %s\n", buf);
}
return 0;
}
/*******client.c*************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main()
{
int ret;
int sockfd;
char buf[256];
struct sockaddr_in srvaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
/* 允許發送廣播 */
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
memset(&srvaddr, 0, sizeof(struct sockaddr_in));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(9999);
srvaddr.sin_addr.s_addr = inet_addr("192.168.2.255");
while(1) {
fgets(buf, sizeof(buf), stdin);
ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
if (ret == -1) {
perror("sendto");
return -1;
}
}
return 0;
}
組播(multcast)
單播方式只能發給一個接收方
廣播方式發送給所有的主機。過多的廣播會大量佔用網絡帶寬,造成廣播風暴,影響正常通信
組播(也叫多播)是一種折中的方式。只有加入某個多播組的主機才能收到數據
網絡地址的D類地址是組播地址:不分網絡地址和主機地址,第一字節的前4位固定爲1110,224.0.0.1~239.255.255.255
組播發送:
1.創建用戶數據報套接字
2.接收方地址指定爲組播地址
3.指定端口信息
4.發送數據包
組播接收:
1.創建用戶數據報套接字
2.加入組播組
3.綁定IP地址(加入的組的組IP或者0.0.0.0)和端口
4.等待接收數據
/*****server.c************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main()
{
int ret;
int sockfd;
char buf[256];
struct sockaddr_in srvaddr;
struct sockaddr_in cltaddr;
socklen_t addrlen;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
//加入組播組
struct ip_mreqn mrq;
memset(&mrq, 0, sizeof(mrq));
mrq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");
mrq.imr_address.s_addr = htonl(INADDR_ANY);
setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mrq, sizeof(mrq));
//bind
memset(&srvaddr, 0, sizeof(struct sockaddr_in));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(9999);
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(sockfd, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
if (ret == -1 ) {
perror("bind");
return -1;
}
printf("dsdgfsdg\n");
while(1) {
memset(buf, 0, sizeof(buf));
addrlen = sizeof(struct sockaddr);
ret = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&cltaddr, &addrlen);
if (ret == -1) {
perror("recvfrom");
return -1;
}
printf("buf : %s\n", buf);
}
return 0;
}
/*****client.c**************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
int main()
{
int ret;
int sockfd;
char buf[256];
struct sockaddr_in srvaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
memset(&srvaddr, 0, sizeof(struct sockaddr_in));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(9999);
srvaddr.sin_addr.s_addr = inet_addr("224.10.10.1");
while(1) {
fgets(buf, sizeof(buf), stdin);
ret = sendto(sockfd, buf, sizeof(buf), 0, (const struct sockaddr *)&srvaddr, sizeof(struct sockaddr));
if (ret == -1) {
perror("sendto");
return -1;
}
printf("ret = %d\n", ret);
}
return 0;
}