1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 网络编程-Socket套接字(TCP UDP 广播和组播通信)

网络编程-Socket套接字(TCP UDP 广播和组播通信)

时间:2020-03-11 18:34:59

相关推荐

网络编程-Socket套接字(TCP UDP 广播和组播通信)

socket套接字

socket是一个编程接口(网络编程接口) 作用是用来实现网络上不同的主机的应用进程之间进行双向通信

套接字是一种特殊的文件描述符也就意味着我们使用套接字实现网络通信的时候可以用read/write

比如:客户端可以用write发送网络数据 服务器端可以用read去接收网络数据

要通过互联网进行通信 至少需要一对套接字 其中一个运行在客户端 称之为Client Socket

另一个运行在服务器端 称之为Server Socket

Socket可以分为三种类型:

1) 流套接字(SOCK_STREAM)

流套接字用于提供面向连接 可靠的数据传输服务

主要针对传输层协议为TCP协议的应用

如果等待我们所写的代码利用TCP协议来通信的话 那么我们就需要创建一个流套接字

2) 数据报套接字(SOCK_DGRAM)

数据报套接字提供一种无连接的服务(并不能保证数据传输的可靠性)

主要针对传输层协议为UDP协议的应用

3) 原始套接字(SOCK_RAW)

TCP UDP 特点

TCP特点:

1、tcp是面向连接的,通信之前需要建立连接,通信结束之后还需释放连接**(三次握手,四次挥手)**

2、tcp提供了很可靠的支付服务,可靠也就是说:tcp的数据没有重复、没有丢失、没有错误、并且和发送端的数据是一致的。

3、tcp是面向字节流的。也就是tcp是以字节为单位,虽然传输的过程中数据被划分为了一个一个数据报文,但是这只是为了方便传输,接收端最终接受到的数据和发送端接收到的数据是一样的。

4、tcp提供全双工通信:就是tcp的两端即可以作为发送端,也可以作为接收端。

5、最重要的一点就是一个tcp的连接只能有两个端点,支持一对一通信。

6、tcp首部含有20个字节。

UDP特点:

1、首先udp是无连接的,通信结束也不需要释放连接。

2、upd是一种不可靠的协议,发出去就不管了。

3、udp是一种面向报文的链接,udp数据传输的单位是报文,而且不会对数据做任何的拆分和拼接操作。在发送端,应用程序给传输层的udp什么样的数据,udp不会对数据进行拆分,最会增加一个udp头并且交给网络层。在接收端,udp收到网络层的数据之后,除去ip(网络层协议)数据报头部后便交给应用层,不会做任何的拼接操作。

4、udp是不存在拥塞控制的,并且始终就是用恒定的速率发送数据,并不会根据网络拥塞情况对发送速率做调整。这个状况下就会存在优势和弊端;弊端就是:网络拥塞时有些报文就会丢失,所以才说udp是不可靠的协议;他的优点就是有些使用场景允许报文丢失,比如:直播,语音通话,但是对实时性要求比较高。

5、udp支持一对一,一对多,多对多,多对一通信

6、udp首部的开销比较小,只有8个字节。相对于tcp来说,效率还是很高的。

TCP UDP 优缺点

TCP优点:可靠,稳定。tcp的可靠体现在tcp在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认,窗口,重传,拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。

TCP缺点:速度慢,效率低,占用系统资源高,易被攻击。TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制,重传机制,拥塞机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU,内存等硬件资源。而且,因为TCP有确认机制,三次握手机制,这些也导致TCP容易被人利用,实现DOS,DDOS,CC等攻击。

UDP优点:速度快,比TCP稍安全。UDP没有TCP的握手,确认,窗口,重传,拥塞控制等机制。UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。但UDP也是无法避免攻击的。比如:UDP Flood攻击。

UDP缺点:不可靠,不稳定。因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会容易丢包。

————————————————

版权声明:本文为CSDN博主「晗二狗」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:/skitan/article/details/107444486

TCP套接字编程流程:

TCP网络应用的数据传输的大概过程 建立连接 “三次握手”发送/接收网络数据 write/send/sendto read/recv/recvfrom 关闭连接 “四次挥手”

为什么会有三次握手的机制?

通信双方成功通信的前提条件是双方都要能够建立连接。

那么双方都能连接到一起的前提条件是什么呢?

必须双方都能够收和发。

就比如x想跟y聊天 在聊天之前就需要测试x和y能否能聊天,如果不能聊天 则不建立连接。

比如:x是聋子(不能收)或则y是哑巴(不能发) 则连接就不能成功建立, 只有当x和y都不

是聋子和哑巴的时候 连接才能建立成功!

所以三次握手实际上就是一个测试能不能建立连接的过程。

第一次握手就是测试客户端能不能发

第二次握手就是测试服务器端能不能收和发

第三次握手就是测试客户端能不能收

“四次挥手”:

建立连接是非常重要的 他是数据正确传输的前提 断开连接 他让计算机释放不再使用的资源

四次挥手的具体过程: 建立连接后客户端和服务器端都处于ESTABLISHED状态 客户端发起断开连接的请求1)客户端调用close函数 向服务器发送FIN数据包 进入FIN_WAIT_1状态 FIN就是表示断开连接 FINISH 2)服务器收到数据包后 检测到设置了FIN标志位 知道要断开连接。于是向客户端发送”确认包“键入CLOSE_WAIT 注意:服务器收到请求后并不是立即断开连接 而是先向服务器端发送”确认包“告诉他我知道了 我需要准备一下才能断开连接 3)客户端收到”确认包“ 后进入FIN_WAIT_2状态 等待服务器准备完毕之后再发一个数据包过来 4)等待片刻之后 服务器准备完毕了 可以断开连接 于是再主动地向客户端发送FIN 告诉它我准备好了 断开连接把 然后进入LAST_ACK状态 5)客户端收到服务器地FIN包后 再向服务器发送ACK包 告诉他你断开连接把 然后进入TIME_WAIT状态 6)服务器收到客户端的ACK包后 就断开连接 关闭套接字 进入CLOSED状态

利用Socket套接字实现TCP通信和UDP通信的函数流程

TCP Server: socket : 绑定一个套接字 bind : 把一个套接字和一个网络地址绑定在一起 如果你想让其他人来主动连接或联系你 你就需要bind一个地址 并把这个地址告诉别人 不调用bind 并不代表你得socket没有地址, 相反 调不调用bind socket在通信的时候 内核都会动态地为你的socket指定一个地址listen: 让套接字进入一个”监听模式“accpet: 接收客户端的连接 多次调用accept就可以与不同的客户端建立连接write/send/sendto or read/recv/recvfrom close/shutdown : ”四路挥手“

代码实现:

#include <sys/types.h>/* See NOTES */#include <sys/socket.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>int flag=0;void sys_erro(char * str){perror(str);}int main(int argc,char * argv[]){if(argc!=3){return -1;}//创建套接字int sock_fd=socket(AF_INET,SOCK_STREAM,0); //ipV4if(-1==sock_fd)sys_erro("socket error\n");//指定服务器struct sockaddr_in serv;serv.sin_family=AF_INET;serv.sin_port=htons(atoi(argv[2])); //端口号 转成16bitsserv.sin_addr.s_addr=inet_addr(argv[1]); //ipint ret=bind(sock_fd,(struct sockaddr*)&serv,sizeof(serv));//绑定网络地址if(-1 == ret){close(sock_fd);sys_erro("bind error\n");}//监听套接字int listen_ret=listen(sock_fd,10);if(-1 == listen_ret){close(sock_fd);sys_erro("listen error\n");}//阻塞等待连接struct sockaddr_in Client;socklen_t len=sizeof(Client);while (1){int accept_ret=accept(sock_fd,(struct sockaddr*)&Client, &len);if(-1 == accept_ret){sys_erro("accept error\n");}printf("connet [%s] [port:%d]\n",inet_ntoa(Client.sin_addr),ntohs(Client.sin_port));pid_t pid=fork();if(pid==0){while (1){char buf1[1024]={0}; //写char buf2[1024]={0}; //读int Rret;//接收Rret=recv(accept_ret,buf2,sizeof(buf2),0);if(Rret==-1){sys_erro("recv error\n");}else if(Rret>0){if(strncmp(buf2,"SeeYou",6)==0){close(accept_ret);flag=1;break;}printf("服务器接收:%s\n",buf2);}//发送fgets(buf1,1023,stdin); //键盘输入send(accept_ret,buf1,strlen(buf1),0);}}else if(pid>0){close(accept_ret);}else{sys_erro("fork erro\n");}if(flag==1){break;}}close(sock_fd);printf("服务器关闭\n");}

TCP Client: socket : 绑定一个套接字 bind : 可要可不要 connect : 主动与TCP Server建立连接 ”三次握手“write/send/sendto or read/recv/recvfrom close/shutdown

代码实现:

#include <sys/types.h>/* See NOTES */#include <sys/socket.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>int sys_erro(char * str){perror(str);return -1;}int main(int argc,char * argv[]){if(argc!=3){return -1;}//创建套接字int sock_fd=socket(AF_INET,SOCK_STREAM,0);if(-1==sock_fd)sys_erro("socket error\n");//指定服务器struct sockaddr_in serv;serv.sin_family=AF_INET;serv.sin_port=htons(atoi(argv[2])); //端口号 转成16bitsserv.sin_addr.s_addr=inet_addr(argv[1]); //ip//请求连接int connect_ret=connect(sock_fd,(struct sockaddr*)&serv,sizeof(serv));if(connect_ret==-1){close(sock_fd);sys_erro("connect error\n");}while (1){int Rret;char buf1[1024]={0}; //写char buf2[1024]={0}; //读//键盘写fgets(buf1,1023,stdin);write(sock_fd,buf1,strlen(buf1));if(strncmp(buf1,"SeeYou",4)==0){break;}//读 Rret=recv(sock_fd,buf2,sizeof(buf2),0);printf("%s\n",buf2);}close(sock_fd);}

UDP Server: socket : 绑定一个套接字 bind : 把一个套接字和一个网络地址绑定在一起 如果你想让其他人来主动连接或联系你 你就需要bind一个地址 并把这个地址告诉别人 write/send/sendto or read/recv/recvfrom close/shutdown

UDP Client: socket : 绑定一个套接字 write/send/sendto or read/recv/recvfrom close/shutdown

套接字选项

每个套接字再不同的协议层次(级别level)上有不同的行为属性(选项) 有两个函数用于获取/设置套接字的选项

getsockopt : 获取套接字的选项 setsockopt : 设置套接字的选项

#include <sys/types.h>/* See NOTES */#include <sys/socket.h>int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);函数参数: sockfd: 你要设置哪个套接字的选项 level: 你要获取的套接字的选项是属于哪个level ---> “查表”optname:你要获取的那个套接字选项的“名字”宏 ---> “查表”optval:指向一段空间 这段空间用来保存获取到的选项的值的 因为不同的选项 值的类型不同 如: SO_RCVBUF-> int * SO_SNDTIMEO -> struct timeval * ...optlen: 指向一段空间 这段空间保存获取到的选项值的数据长度的 返回值: 成功返回0 失败返回-1 并且errno被设置int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);函数参数: 前面三个跟上面函数类型 指定你要设置哪个套接字的具体哪个选项 optval:指向一段空间 这段空间里面保存了你要设置的值optlen:你要设置的选项值所占的空间的长度 返回值: 成功返回0 失败返回-1 并且errno被设置

广播和组播(多播)

1.广播 broadcast

广播就是向局域网内所有的人说话 但是广播还是要指定接收者的端口号的

a.只有传输层协议是UDP协议的时候 才支持广播

因为TCP是端对端 广播是一对多

b.广播地址

广播地址是专门用于同时向网络中所有工作站进行发送的一个地址

子网内广播地址:主机号全为1的IP地址就是广播地址

2.多播(组播)multicast

单播用于两个主机之间的端对端的通信 广播用于一个主机对整个局域网上所有的主机进行通信

单播和广播是两个极端

有时候 我们需要对一组特定的主机进行通信 --> 多播

也就是说处于同一组的主机就能收到数据 不在同一组的主机就收不到数据—》类似于QQ群

注意:

a.多播也只有传输层协议为UDP时 才支持多播(组播)功能

b.多播地址是IPV4的D类地址

D 1110多播组号(28bit) 224.0.0.0 - 239.255.255.255

多播的编程思路:

多播同样分为服务器(多播发送者)和客户端(多播接收者)

服务器(多播发送者):

1.创建一个套接字 --》 UDP的套接字 2.通过sendto发送信息到一个多播组地址中 多播组地址: D类IP地址 + PORT3.关闭套接字 注意:服务器(多播发送者)不需要加入多播组 就可以直接向某个多播组发送数据 而如果你想要接收数据 那么就必须要加入多播组

代码实现:

客户端(多播接收者)

1.创建一个套接字--》UDP的套接字 2.加入一个多播组 3.绑定地址 绑定多播组的地址 --》 D类IP + PORT4.接收多播组的信息 5.也可以发送信息到多播组 6.关闭套接字

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。