网络编程-------初学者入门
一、网络相关基础知识
1、网络存在的意义
用来做跨主机进程间的通讯,在不同的主机间进行数据交换
2、局域网
①一个小范围内的主机组成的网络 一般是由一个路由器构建的
②局域网内的主机可以互相通讯
③不能链接外网
3、广域网
把无数个局域网连接在一起 组成的就是广域网
①通过网络运营商
②可以链接外网
4、连接服务器的流程
比如:https://www.baidu.com/
① 输入www.baidu.com
② 访问DNS服务器,然后DNS服务器将域名解析成IP
③ 通过解析拿到的ip地址访问百度服务器
5、IP地址的分类
5.1 TCP/IP协议架构与OSI七层模型:
TCP/IP协议:传输控制/网际协议(Transfer Control Protocol/Internet Protocol) 又称作网络通讯协议。是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成
5.2 什么是IP地址以及它的作用?
IP地址(Internet Protocol Address)是指互联网协议地址,又名网络通讯协议。
IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,用来区分网络中不同的计算机,网络中的IP地址是唯一的,不会出现两台电脑的IP地址一样的情况。IP地址是用点分十进制的形式表示的 A.B.C.D
IPV4:用来给每个上网的设备 都分配一个ip地址 IPV4的地址 4个字节
IPV4地址的范围 0.0.0.0 - 255.255.255.255 最多支持 256*256*256*256个地址
运营商:临时ip,当你的设备联网的时候 会去ip池 找一个能用ip,把这个ip给你,当你的设备不联网的时候 马上回收这个ip
IPv6:16字节 128位 能分配的地址会更多,但目前IPv6还没有铺开,仅支持,但不可用
5.3 IP地址是由两部分组成的,一个是网络id,一个是主机id,网络id指明你的计算机处于哪一个网段,主机id指明这个网段当中的具体哪一台计算机。
IP地址分为五类:
A类:A类地址一般是超大型的企业使用
第一个字节是固定的(网络ID),后边三个字节是可变的(主机ID)
范围: 1.0.0.0-127.255.255.255
有127个A类地址,每个A类地址可以链接256*256*256个设备
B类:主要用于大型的企业
前两个字节是固定的(网络ID),后两个字节可变(主机ID)
范围: 128.0.0.0-191.255.255.255
B类地址的个数:(192-128)*256
一个B类地址可以链接256*256个设备
C类:主要用于局域网
前三个字节是固定的(网络ID),后一个字节可变(主机ID)
范围: 192.0.0.0-223.255.255.255
C类地址的个数:(224-192)*256*256
一个C类地址最多连255个设备
D类:组播地址
范围: 224.0.0.0-239.255.255.255
E类:保留地址
范围:240.0.0.0-255.255.255.255
6、端口号
假如系统里启动很多个进程
比如手机 玩着王者 开着微信 QQ。借助于端口号可以来区分我要跟哪个进程进行通讯
端口号:他就是一个16位的无符号整型数 范围:0-65535
1-1023:被系统占用
1024~49150:注册端口(可用)
49151~65535:动态或私有端口
要想通过网络去访问到某一个进程 必须要有端口号
访问一个服务器的时候 假如使用的是http或者是https协议
http:常见的端口 80 8080
https:常见的端口 443 8443
7、网络字节序
大端模式:高字节存放在低地址位,低字节存放在高地址位
小端模式:高字节存放在高地址位,低字节存放在低字节位
电脑:用的是小端模式
网络传输的时候:用的是大端模式
端口号转换:(小端转大端)
uint32_t htonl(uint32_t hostlong);//本函数将一个32位数从主机字节顺序转换成无符号长整型网络字节顺序 host to network long (将小端模式的端口转换成长整型)
uint16_t htons(uint16_t hostshort);//将一个无符号短整型的主机数值转换为网络字节顺序
host to network short (将小端模式的端口转换为无符号16位短整型)
端口号转换:(大端转小端)
uint32_t ntohl(uint32_t netlong);//将一个无符号长整形数从网络字节顺序转换为主机字节顺序。
uint16_t ntohs(uint16_t netshort);//将一个16位数由网络字节顺序转换为主机字节顺序。
8、网络通讯 (重要)
TCP:在通讯之前必须要建立一个网络链接,提供一个可靠的文件传输,效率略低
UDP:在通讯之前不需要建立网络链接,提供的是不可靠的文件传输,效率略高
TCP和UDP的区别: TCP:提供一个面向链接的可靠文件传输
UDP:提供一个面向非链接的不可靠文件传输
它们的通信都是使用的套接字 socket
TCP三次握手:
第一次握手:建立连接时,客户端先发送syn包(seq=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)
第二次握手:服务器收到syn包,必须确认客户端的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
简记:①客户端先发送syn包到服务器;②服务端发送ack包和自己的syn包;③向服务器发送确认包 ACK包
UDP协议编程框架:
TCP协议编程框架:
TCP三次握手建立连接:
1、将小端模式的IP地址 转换成大端模式 inet_addr (重要)
在网络中,IP地址是用网络字节序进行通信的,但是咱们使用的时候用的点分十进制,所以在进行网络中通信的时候,需要提前把IP地址进行转换,转换成网络字节序,也就是32位网络字节序。点分十进制形式:将地址的4个字节写成十进制数字
网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位
函数的功能:将点分十进制的IPv4地址转换成 网络字节序列的长整型
函数的头文件:#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函数的原型:in_addr_t inet_addr(const char *cp);
函数的参数:const char *cp:要转换的IP地址
函数的返回值:成功返回 大端模式
例: inet_addr("192.168.10.1")
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{in_addr_t addr;addr = inet_addr("192.168.18.127");//单独使用时,地址的第四个数范围为0-127if(addr<0){perror("inet_addr");return -1;}printf("addr:%d\n",addr);return 0;
}
//addr:2131929280
解释:例如 inet_addr(“192.168.2.80”)的返回值,其返回值为:1342351552,这是十进制的表示方法;如果转换成2进制则为:01010000000000101010100011000000 (这个就是网络字节序),如果将上面每8位二进制中间加个".",则变成01010000.00000010.10101000.11000000,再将上面的二进制再转回成十进制,则变成了80.2.168.192,会发现与上面的192.168.2.80是相反的,即如果原来的a.b.c.d,现在经过转换就变成了d.c.b.a;
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
暂时为了解内容:
①只用于IPV4:(了解)
int inet_aton(const char *cp, struct in_addr *inp); //点分十进制IP --> 网络字节的32位二进制数值
char *inet_ntoa(struct in_addr in); //网络字节的32位二进制数值-->点分十进制IP
②可用于IPV4和IPV6:(了解)
int inet_pton(int af, const char *src, void *dst);//类比inet_aton 192.168.10.1 --> 11000000 10101000 00001010 00000001
const char *inet_ntop(int af, const void *src,char *dst, socklen_t cnt); 11000000 10101000 00001010 00000001 --> 192.168.10.1
af:AF_INET:表示为ipv4 AF_INET6:表示为ipv6
2、将点分的数 转换为网络字节序的整形 inet_pton
函数的功能:将点分十进制IP 转换为网络字节序的整型
函数的头文件:#include <arpa/inet.h>
函数的原型:int inet_pton(int af, const char *src, void *dst);
函数的参数:af:要转换的ip的类型 AF_INET:ipv4 AF_INET6:ipv6
const char *src:点分十进制的字符串
void *dst:存放转换后的整形
函数的返回值:成功返回 0 失败返回 非零
3、将网络字节序的整形数 转换成字符串 inet_ntoa
函数的功能:点分十进制IP-->网络字节的32位二进制数值并返回
函数的头文件:#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函数的原型:char *inet_ntoa(struct in_addr in);
函数的参数:in:网络字节序的整形数 存放的位置
函数的返回值:转换后的字符串的首地址
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
二、套接字编程
什么叫做套接字:套接字可以理解成一个特殊的文件的文件描述符,我们可以对这个描述符进行读或者写 关闭,具有很多种功能的文件
创建的时候需要借助socket函数:
①套接字可以绑定IP和端口
②套接字可以监听整个网络的信息
③还可以设置网络的属性
④可以被别人链接
⑤可以链接别人
1、创建一个套接字 socket (重要)
函数的功能:创建一个套接字
函数的头文件:#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:int socket(int domain, int type, int protocol);
函数的参数:int domain:IP的类型(AF_INET:ipv4、 AF_INET6:ipv6)
int type:IP协议的类型
SOCK_STREAM:TCP协议 流式套接字 (提供可靠的、面向连接的通信流,保证数据传输的正确性和顺序性)
SOCK_DGRAM: UDP协议 数据报(无连接的服务,独立报文传输,无序,不保证是可靠、无差错的)
int protocol:固定填 0
函数的返回值:成功返回 套接字的文件的文件描述符
文件描述符跟非缓冲区文件操作里的文件描述符 起始位置是一样的,套接字也是从 3开始的,0 1 2默认的被分配为 标准输入 标准输出 标准错误
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>int main()
{int sockfd;sockfd=socket(AF_INET,SOCK_STREAM,0);//使用TCP协议printf("sockfd:%d\n",sockfd);return 0;
}
//sockfd:3
2、绑定服务器的属性(端口、IP) bind
函数的功能:将创建的监听套接字和核心结构体进行绑定
函数的头文件:#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
函数的参数:int sockfd:套接字
const struct sockaddr *addr:填写的核心结构体(服务器的ip端口 以及协议类型)
socklen_t addrlen:核心结构体的大小
函数的返回值:成功返回 0 失败返回 -1
struct sockaddr { //此结构不常用
sa_family_t sa_family; ipv4或者ipv6
char sa_data[14]; 包含ip端口,最多使用14个字符长度
}
struct sockaddr_in { 头文件:#include<netinet/in.h> //常用结构体
sa_family_t sin_family; ipv4还是ipv6
in_port_t sin_port; 端口号
struct in_addr sin_addr; 存放ip地址的结构体
};
struct in_addr {
uint32_t s_addr; ip地址
};
绑定ip 地址 绑定自己的ip即可
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>struct sockaddr_in seraddr;
int main()
{int sockfd,ret;sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){perror("socket");return -1;}seraddr.sin_family=AF_INET;seraddr.sin_port=htons(8888);seraddr.sin_addr.s_addr=inet_addr("192.168.18.131");ret=bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr));if(ret < 0){perror("bind");return -1;}printf("ret:%d\n",ret);return 0;
}
//ret:0
3、监听整个网络 listen
函数的功能:设置最大的监听数
函数的头文件:#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:int listen(int sockfd, int backlog);
函数的参数:int sockfd:套接字
int backlog:你要监听的客户端的个数,这里最大为128
函数的返回值:成功返回 0 失败返回 -1
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
int main()
{int sockfd,set;sockfd=socket(AF_INET,SOCK_STREAM,0);set=listen(sockfd,10);if(set < 0){perror("listen");return -1;}printf("set:%d\n",set);return 0;
}
//set:0
4、接受客户端的链接 accept
函数的功能:和客户端建立连接
函数的头文件:#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数的参数:int sockfd:服务端的套接字
struct sockaddr *addr:客户端的核心结构体(用于和客户端建立连接之后保存客户端的信息,IP地址和端口号)
socklen_t *addrlen:存放客户端的核心结构体大小的指针
函数的返回值:成功返回 服务器给我们虚拟出来的一个套接字,专门用来跟客户端进行通讯,假如没有客户端连接服务器 他就会阻塞 失败返回 -1
5、接收消息 recv
函数的功能:使用通信套接字接收发来的消息
函数的头文件:#include <sys/types.h>
#include <sys/socket.h>
函数的原型:ssize_t recv(int s, const void *buf, size_t len, int flags);
函数的参数:int s:通信套接字accept函数的返回值
const void *buf:接收到消息存放的位置
size_t len:接收消息的大小
int flags:一般写0 读取不到就阻塞
函数的返回值:成功返回 接收到的消息的字节数 失败返回 -1 返回0,表示客户端下线
6、发送消息 send
函数的功能:使用通信套接字发送消息
函数的头文件:#include <sys/types.h>
#include <sys/socket.h>
函数的原型:ssize_t send(int s, const void *buf, size_t len, int flags);
函数的参数:int s:通信套接字accept函数的返回值
const void *buf:要发送的消息的内容
size_t len:消息内容的大小
int flags:一般写0 发送不了就阻塞
函数的返回值:成功返回 发送消息的字节大小 失败返回 -1
7、连接服务器 connect
函数的功能:向服务器发出连接请求
函数的头文件:#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
函数的参数:int sockfd:创建的套接字,socket的返回值
const struct sockaddr *addr:服务端地址的结构体
这个结构体里包含了:IP的类型、IP地址、服务器的端口
socklen_t addrlen:服务端的地址结构体的大小
函数的返回值:成功返回 0 失败返回 -1
8、关闭套接字 close
#include <stdio.h> //TCP服务端流程,仅能接收一次消息
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
struct sockaddr_in seraddr;
struct sockaddr cliaddr;
int main()
{int sockfd;//创建一个套接字sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("socket");return -1;}//绑定服务器信息, 失败的可能性比较大seraddr.sin_family=AF_INET;seraddr.sin_port=htons(9999);//小端转大端 //端口号,要合法seraddr.sin_addr.s_addr=inet_addr("192.168.18.133");//真实存在的ID,可以写自己的IDif(bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr))<0){perror("bind");return -1;}//监听网络if(listen(sockfd,10)<0){perror("listen");return -1;}//接收客户端的链接int cfd;socklen_t len;cfd=accept(sockfd,&cliaddr,&len);if(cfd<0){perror("accept");return -1;}//此处接收客户端发来的消息char buf[15];memset(buf,0,sizeof(buf));//清空buf中的内容,初始化recv(cfd,buf,10,0);printf("buf:%s\n",buf);//发送一条到客户端消息send(cfd,"hello",5,0);//关闭套接字close(sockfd);return 0;
}
#include <stdio.h> //一个客户端可以不停地发送消息,服务端可以不断地接收消息
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
struct sockaddr_in seraddr;
struct sockaddr cliaddr;void *myfunc(void *arg)
{char buf[10];int cfd=*((int *)arg);printf("cfd:%d\n",cfd);while(1){memset(buf,0,sizeof(buf));recv(cfd,buf,10,0);printf("buf:%s\n",buf);//发送一条到客户端消息send(cfd,"hello",5,0);//如果有一个客户端链接之后,就不发消息,那么就会发生阻塞,服务端就无法接收新的客户端,所以此时要使用多线程,专门处理这个客户端的问题}
}int main()
{int sockfd;//创建一个套接字sockfd=socket(AF_INET,SOCK_STREAM,0);if(sockfd<0){perror("socket");return -1;}//绑定服务器信息, 失败的可能性比较大seraddr.sin_family=AF_INET;seraddr.sin_port=htons(9999);//小端转大端 //端口号,要合法seraddr.sin_addr.s_addr=inet_addr("192.168.18.133");//真实存在的ID,可以写自己的IDif(bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr))<0){perror("bind");return -1;}//监听网络if(listen(sockfd,10)<0){perror("listen");return -1;}//接收客户端的链接int cfd;socklen_t len;
while(1)
{pthread_t pthid;cfd=accept(sockfd,&cliaddr,&len);//此处接收客户端发来的消息pthread_create(&pthid,NULL,myfunc,(void *)&cfd);
}//关闭套接字close(sockfd);return 0;
}
三、UDP通讯
非连接、不可靠、速度更快、多用于音频播放 视频播放。udp可以用来组件广播或者组播、广播和组播一般存在于局域网内
1、接收udp报文 recvfrom
函数的功能:接收udp的消息
函数的头文件:#include <sys/types.h>
#include <sys/socket.h>
函数的原型:ssize_t recvfrom(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
函数的参数:int s:通信套接字accept函数的返回值
const void *buf:接收到的消息的存放位置
size_t len:接收的消息的大小
int flags:一般写 0 接收不到就阻塞
const struct sockaddr *to:客户端的核心结构体(服务端状态下,接收客户端信息)
socklen_t tolen:客户端的核心结构体的大小(服务端状态下)
函数的返回值:成功返回 接收消息的字节大小 失败返回 -1
2、发送UDP的报文 sendto
函数的功能:发送udp消息
函数的头文件:#include <sys/types.h>
#include <sys/socket.h>
函数的原型:ssize_t sendto(int s, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
函数的参数:int s:通信套接字accept函数的返回值
const void *buf:要发送的消息的内容
size_t len:要发送内容的大小
int flags:一般写 0 不送不了就阻塞
const struct sockaddr *dest_addr:要发送的对象的核心结构体
socklen_t addrlen:要发送的对象的核心结构体的大小
函数的返回值:成功返回 成功发送消息的字节大小 失败返回 -1
#include<stdio.h> //UDP服务端
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
struct sockaddr_in seraddr,cliaddr;
int main()
{//1:创建一个套接字int sockfd,ret;char buf[32];socklen_t len;sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){perror("socket");return -1;}//2:绑定服务器的ip端口seraddr.sin_family=AF_INET;seraddr.sin_port=htons(8888);seraddr.sin_addr.s_addr=inet_addr("192.168.18.133");ret=bind(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr));if(ret < 0){perror("bind");return -1;}while(1)//循环接收客户端发来的消息{//3:接收客户端发来的消息len=(socklen_t)sizeof(cliaddr);memset(buf,0,sizeof(buf));//初始化buf,防止里面存在有杂乱的东西recvfrom(sockfd,buf,10,0,(struct sockaddr *)&cliaddr,&len);//printf("len=%d\n",len);printf("buf=%s\n",buf);//printf("client:%s\n",inet_ntoa(cliaddr.sin_addr));//4:发送一条消息到客户端printf("hhhhh:%ld\n",sendto(sockfd,"hi!",5,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr)));}return 0;
}
#include<stdio.h> //UDP客户端
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
#include<unistd.h>int main()
{//1:创建一个套接字int sockfd;socklen_t len;char buf[10];struct sockaddr_in seraddr,seraddr1;sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd < 0){perror("socket");return -1;}//2:发送消息seraddr.sin_family=AF_INET;seraddr.sin_port=htons(8888);seraddr.sin_addr.s_addr=inet_addr("192.168.18.133");while(1){sendto(sockfd,"world",5,0,(struct sockaddr *)&(seraddr),sizeof(seraddr));//3:接受消息memset(buf,0,sizeof(buf));recvfrom(sockfd,buf,10,0,(struct sockaddr *)&(seraddr1),&len);printf("clibuf:%s\n",buf);sleep(1);}return 0;
}
四、UDP的组播
组播:假如一个人创建了一个组播,另外一个进程只要加入了这个组播,创建者往组播里发东西,加入组播的所有的人都能收到创建者发的消息。类似于禁言的群聊
udp默认不打开组播和广播,要想打开组播和广播功能,需要借助一个函数:setsockopt。还需要有一个组播的地址:224.0.0.0-239.255.255.255
3、设置套接字的属性 setsockopt
函数的功能:设置linux套接字的属性
函数的头文件:#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
函数的参数:int sockfd:套接字
int level:网络的层 IPPROTO_IP:用于设置组播和广播 SOL_SOCKET:用于快速释放底层ip或者广播
int optname:你要设置的属性
属于IPPROTO_IP:IP_MULITCAST_IF:创建一个多播组 IP_ADD_MEMBERSHIP:加入一个多播组
属于SOL_SOCKET:SO_REUSEADDR:快速释放底层ip
SO_BROADCAST:开启套接字的广播
const void *optval:参数依据前面选项的不同,参数也不同
struct ip_mreqn {
struct in_addr imr_multiaddr; 要加入的多播组的ip
struct in_addr imr_address; 自己的ip
int imr_ifindex; 物理网卡的索引号
// if_nametoindex("ens33")
};
struct in_addr {
uint32_t s_addr; ip 地址
};
socklen_t optlen:前面 optval 参数的长度
函数的返回值:成功返回 0 失败返回 -1
#include<stdio.h> //创建一个多播组
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
#include<unistd.h>
#include <net/if.h>
int main()
{//1:创建套接字int sfd,ret;struct sockaddr_in sendaddr;struct ip_mreqn memmsg;sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd < 0){perror("socket");return -1;}//2:创建多播组memmsg.imr_multiaddr.s_addr=inet_addr("224.2.2.2");memmsg.imr_address.s_addr=inet_addr("192.168.18.133");memmsg.imr_ifindex=if_nametoindex("ens33");ret=setsockopt(sfd,IPPROTO_IP,IP_MULTICAST_IF,&memmsg,sizeof(memmsg));if(ret < 0){perror("setsockopt");return -1;}//3:向组播发送消息while(1){sendaddr.sin_family=AF_INET;sendaddr.sin_port=htons(12345);sendaddr.sin_addr.s_addr=inet_addr("224.2.2.2");sendto(sfd,"hello",5,0,(struct sockaddr *)&sendaddr,sizeof(sendaddr));sleep(2);}return 0;
}
#include<stdio.h> //加入一个多播组
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
#include<unistd.h>
#include <net/if.h>
int main()
{struct sockaddr_in cliaddr;struct sockaddr rcvaddr;struct ip_mreqn memmsg;char buf[10];socklen_t len;//1:创建套接字int cid =socket(AF_INET,SOCK_DGRAM,0);if(cid < 0){perror("socket");return -1;}//2:绑定信息cliaddr.sin_family=AF_INET;cliaddr.sin_port=htons(12345);//要与多播组的端口保持一致cliaddr.sin_addr.s_addr=inet_addr("0.0.0.0");bind(cid,(struct sockaddr *)&cliaddr,sizeof(cliaddr));//3:加入一个多播组memmsg.imr_multiaddr.s_addr=inet_addr("224.2.2.2");memmsg.imr_address.s_addr=inet_addr("192.168.18.133");memmsg.imr_ifindex=if_nametoindex("ens33");setsockopt(cid,IPPROTO_IP,IP_ADD_MEMBERSHIP,&memmsg,sizeof(memmsg));while(1){recvfrom(cid,buf,10,0,&rcvaddr,&len);printf("接收到组播消息:%s\n",buf);}return 0;
}
五、netstat
netstat是控制台命令,是一个监控TCP/IP网络的非常有用的工具,它可以监控实际的网络连接以及每一个网络接口设备的状态信息。netstat用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。
查看端口占用情况:netstat -anp | grep 端口号
查看所有已使用的端口情况:netstat -nultp
网络编程-------初学者入门相关推荐
- 新手必看:生成对抗网络的初学者入门指导
新手必看:生成对抗网络的初学者入门指导 https://www.cnblogs.com/DicksonJYL/p/9698877.html 本文为 AI 研习社编译的技术博客,原标题 A Beginn ...
- 网络编程-java入门
网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编程是比较复 ...
- 区块链编程初学者入门指南
我有很多问题需要了解区块链Blockchain的工作原理.重要的是"我如何在其上构建应用程序dapp?".花了几个星期的时间挖掘,阅读和试验才最终了解.我找不到简短而全面的指南.现 ...
- ASP网络编程从入门到精通 下载
<ASP网络编程从入门到精通> 清华大学出版社 特点: 面向ASP零基础读者,循序渐进 全面分析ASP技术细节 用代码描述个个知识点,操作性强 通过典型模块设计,体会ASP的奥妙 通过网上 ...
- java消息头,Java网络编程从入门到精通:HTTP消息头字段
Java网络编程从入门到精通:HTTP消息头字段 一.通用头字段 1. Connection 这个字段只在HTTP1.1协议中存在.它决定了客户端和服务器进行了一次会话后, 服务器是否立即关闭网络连接 ...
- C++网络编程快速入门(四):EPOLL模型使用
目录 基本使用方法 step1:创建epollfd step2:将fd绑定到epollfd step3:调用epoll_wait检测事件 epoll_wait与poll.select区别所在 水平触发 ...
- C++网络编程快速入门(二):Linux下使用select演示简单服务端程序
目录 select参数解释 select使用规范 select使用缺点 基本流程 实例代码 通信效果演示 往期文章 select参数解释 extern int select (int __nfds, ...
- JavaScript_牛客网_编程初学者入门训练(21-30题解)
牛客网编程初学者入门训练题解JavaScript版本 编程初学者入门训练第21-30题解答(js) 22.你能活多少秒 25.计算体重指数 26.计算三角形的周长和面积 27.计算球体体积 28.大小 ...
- java编程题身高排队_编程初学者入门4_从键盘输入5个人的身高(米),求他们的平均身...
编程初学者入门4_从键盘输入5个人的身高(米),求他们的平均身 编程初学者入门4_从键盘输入5个人的身高(米),求他们的平均身高(米).(C的没什么问题,试着用Java写一下,Java的Scanner ...
最新文章
- Sqlite的多表连接更新
- 单片机modebus RTU通信实现,采用C语言,可适用于单片机,VC,安卓等(转)
- python函数代码的复用_Python__函数和代码复用
- C++ Primer 5th笔记(chap 16 模板和泛型编程)类模板定义
- 蛙泳如何找准背部发力的感觉
- 小米 pegasus_使用Google的Pegasus库生成摘要
- 基于bootstrap模态框的日期选择器
- [转载] Python程序输入一个字符串并查找总数的大写和小写字母
- 哪一类功率放大电路效率最高_集成电路工艺之双极型工艺
- 需求分析说明书和需求规格说明书
- activex 控件 过期_ie8/9下Activex控件无法加载的两种解决方法
- Android MVP架构实现
- android+表情符号乱码,Android Emoji表情截取不完整,乱码
- 搭建一个属于自己的服务器,并实现内网穿透(外网访问本地服务器功能)
- 安装Snipe-IT资产管理系统
- 【NOIP2010普及组】三国游戏题解
- Windows远程桌面提示CredSSP加密数据库修正
- 64位系统 system32 和 syswow64
- 安装飞利浦系统服务器,飞利浦电视小飞OS系统最新软件安装教程!
- 2017年的电子设计竞赛快开始了,学放大器的小伙伴们进来一起谈论一下!