socket网络编程之TCP、UDP

发布时间:2024-02-23
系统运维
之前说的用于进程间通信的几种方式:消息signal、管道pipe、消息队列msg、共享内存shm、信号量sem。都只适用于一台主机上的进程间通信,那么如何实现两台计算机之间的进程通信呢?所以,来了解一下异地进程通信。
1 异地进程通信
协议层为双方的主机通信进程分配“端口”和缓冲区,以便异地进程间的通信。
1.1tcp/ip协议
以下是osi参考模型与tcp/ip参考模型的对应关系:
1.1.1 tcp/ip协议族
tcp/ip 协议组大体上分为三部分:
1.internet 协议(ip)
2.传输控制协议(tcp)和用户数据报文协议(udp)
3.处于tcp 和udp 之上的一组协议专门开发的应用程序。它们包括:telnet,文件传送协议(ftp),域名服务(dns)和简单的邮件传送程序(smtp)等许多协议。
应用层协议
telnet
文件传送协议(ftp和tftp)
简单的文件传送协议(smtp)
域名服务(dns)等协议
2 网络编程基础
socket标准被扩展成window socket和unix socket
linux中的网络编程通过socket接口实现。
socket既是一种特殊的io,它也是一种文件描述符。
一个完整的socket 都有一个相关描述{协议,本地地址,本地端口,远程地址,远程端口};每一个socket 有一个本地的唯一socket 号,由操作系统分配。
2.1 socket分类
流式套接字(sock_stream)
流式的套接字可以提供可靠的、面向连接的通讯流。它使用了tcp协议。tcp 保证了数据传输的正确性和顺序性。
数据报套接字(sock_dgram)
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。使用数据报协议udp协议。
原始套接字。
原始套接字允许对低层协议如ip或icmp直接访问,主要用于新的网络协议实现的测试等。
2.2 编程流程
tcp
udp
具体函数的用法,就自己man了。
2.2.1 套接字地址结构
重点讲一下套接字地址结构:
#include < netinet/in.h>struct sockaddr{unsigned short sa_family; /* address族, af_xxx */char sa_data[14]; /* 14 bytes的协议地址 */};sa_family的取值,一般来说,ipv4使用“af_inet”
sa_data包含了一些远程电脑的地址、端口和套接字的数目,里面的数据是杂溶在一起的。一般我们不用这个结构体,因为我们一般使用的地址都是ip 端口号。比如:ip192.168.159.2 port3306 。这样来记录地址。所以一般使用下面这个地址结构,而知数据类型是等效的,可以互相转换。
#include < netinet/in.h>struct sockaddr_in {short int sin_family; /* internet地址族 */unsigned short int sin_port; /* 端口号 */struct in_addr sin_addr; /* internet地址 */unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/};2.2.2 字节序列转换
因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,底位在后,而有的系统是底位在前,高位在后 ),而网络传输的数据大家是一定要统一顺序的。所以对与内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换。
htons()——“host to network short”
主机字节顺序转换为网络字节顺序(对无符号短型进行操作2bytes)
htonl()——“host to network long” 
主机字节顺序转换为网络字节顺序(对无符号长型进行操作4bytes)
ntohs()——“network to host short”
网络字节顺序转换为主机字节顺序(对无符号短型进行操作2bytes)
ntohl()——“network to host long ”
网络字节顺序转换为主机字节顺序(对无符号长型进行操作4bytes)
2.2.3地址格式转换
-linux提供将点分格式的地址转于长整型数之间的转换函数。
inet_addr()能够把一个用数字和点表示ip 地址的字符串转换成一个无符号长整型。
inet_ntoa()能够把网络字节顺序转换为地址结构的数据。
2.2.4基本套接字调用
socket() bind() connect()
listen() accept() send()
recv() sendto() shutdown()
recvfrom() close() getsockopt()
setsockopt() getpeername()
getsockname() gethostbyname()
gethostbyaddr() getprotobyname()
fcntl()
练习1-tcp
tcp连接,等待客户端输入,将内容发送给服务器,并获取客户端地址。
这里,getsocketname()表示获得本地(自己)的地址;
getpeername()表示获得连接上的客户端的地址(源ip地址)。
<br>
server.c
#include < sys/types.h> #include < sys/socket.h>#include < netinet/in.h> //sockaddr_in#include < stdio.h>#include < string.h>int main(){ int fd; int clientfd; int ret; pid_t pid; int addrlen = 0; char acbuf[20] = ; struct sockaddr_in addr = {0}; //自己的地址 struct sockaddr_in clientaddr = {0}; //连上的客户端的地址 //1.socket() fd = socket(pf_inet,sock_stream,0); if(fd == -1) { perror(socket); return -1; } //2.bind() addr.sin_family = af_inet; addr.sin_port = htons(1234); addr.sin_addr.s_addr = inet_addr(192.168.159.6); ret = bind(fd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in)); if(ret == -1) { perror(bind); return -1; } //3.listen() ret = listen(fd,10); if(ret == -1) { perror(listen); return -1; } //4.阻塞 等待 accept() clientfd = accept(fd,null,null); if(clientfd == -1) { perror(accept); return -1; }//获取客户端地址addrlen = sizeof(struct sockaddr_in);ret = getpeername(clientfd, (struct sockaddr *)&clientaddr, &addrlen);if(ret == -1){ perror(getpeername); return -1;}printf(client login.\\\\nip: %s , port: %d\\\\n,inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));//5.通信while(1){ memset(acbuf,0,20); if (read(clientfd,acbuf,20) > 0) { printf(receive: %s\\\\n,a
上一个:电机马达的型号选择需要根据实际应用情况
下一个:电脑不通电开不了机怎么办(电脑不通电开不了机风扇都不动)

bios查看硬盘序列号,如何在华硕主板BIOS看硬盘信息
u盘怎么免疫病毒(u盘病毒创建文件夹)
电脑程序安装,平板电脑程序安装
编码器选择指南:如何选择最合适自己的编码器?
石作加工“做糙”与“剁斧”如何区分?计算工程量的一般规定是什么?
普洱茶的香气中,最有价值的居然是这些!
ST - 如何为汽车智能配电系统选择功率开关管
怎样把win7升级win10系统(如何将win7升级到win10)
学设计画图用什么笔记本,学设计用什么样的笔记本
深藏时光里的好茶