socket网络编程一:socket介绍及函数原语

马谦马谦马谦 2018年3月9日11:32:13 发表评论
文章最后编辑于:2018-11-15 11:09:59

socket计算机中的一种网络传输机制,对TCP和UDP的封装,自动帮我们在底层完成各种协议操作,接收到数据包后返回到上层应用。

socket分为客户端和服务端,它的工作模型为:

socket网络编程一:socket介绍及函数原语

一、socket 网络地址

1.1 网络字节序

关于字节序的概念可以查看计算机中的字节序

一般来说,计算机是低字节序,网络传输是高字节序,两者之间并不统一。使用时需要通过以下函数进行转换:

记忆方式

h表示host,n表示network,l表示32位长整数,s表示16位短整数。

例如端口号是16位(s),主机(h)转网络(n)字节序的函数为htons

1.2 IP地址转换函数

socket地址

计算机中的IP地址是一个32位长整数,因为ip地址最多为255.255.255.255,每个点位最多占1个字节=8位,所以IP地址为32位整数。

我们用的地址是一个sockaddr类型,它包含了地址族,端口号和IP地址等信息。不过它是很早以前的地址结构了,为了适应需要,现在衍生出了sockaddr_in等地址类型如下图所示。

socket网络编程一:socket介绍及函数原语

但是为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。类型的定义如下:

一般我们常用的是sockaddr_in,简单用法为:

地址转换函数

早期IPv4地址转换函数:

在后期引入IPv6后的转换函数支持IPv4和IPv6:

其中af是地址族,一般填写AF_INET表示以太网。

二、socket操作函数

2.1 socket

socket函数用于创建一个socket对象,在linux环境中,socket也是一个文件,因此该函数实际返回的是一个文件描述符。

参数说明

2.2 bind

bind用于绑定地址到socket。

参数说明

绑定前要先设置好地址:

2.3 listen

listen用于监听某个端口号:

参数说明

查看系统默认backlog

典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。

2.4 accept

服务端接受一个socket连接,此时的连接已经三次握手完成

参数说明

三次握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-resultargument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给addr参数传NULL,表示不关心客户端的地址。

2.5 connect

客户端连接服务端的函数,此时开始三次握手。

参数说明:

2.6 recv和recvfrom

recv用于TCP协议读取数据:

recv用于udp协议,参数含义类似。

由于socket也是一个文件描述符,因此也可以使用read来读取socket中的数据。

2.7 send和sendto

send和sendto分别用于tcp和udp协议,参数含义和上面的recv类似,也可以使用write向socket中些数据。

三、一个简单的服务端和客户端案例

以下是一个示例demo,客户端在连接上服务端后输入相应的字符串发送过去,然后服务端把所有字符转成大写返回。

运行结果

服务端通过./server 9988启动,监听9988端口。客户端连接端口输入字符串测试:

服务端显示:

本文共执行46次查询,耗时0.287秒!
马谦马谦马谦

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: