套接字到底是什么,套接字是TCP协议吗? 我们平时很多方面都用插座,你真的知道插座吗?
一.说到插座,我们在说什么? 维基百科3360 anetworksocketisanendpointofaconnectioninacomputernetwork.internetprotocol (IP ) networks,theseareoftencall thataprogramcanpasstothenetworkingapplicationprogramminginterface (API ) tousetheconnectionforreceivingandsendingdata.socke
个人理解:插座其实是通信电缆两端的电话终端,电话接通后相当有两个插座相连,两个电话之间可以相互通话,两个插座之间可以实时发送和接收数据,插座只有一个通信工具(TCP、UDP、HTTP才是我们普遍理解的协议。
这意味着套接字这一工具一般使用两种协议进行通信: TCP和UDP。 否则,灯杆插座就不会长毛了。 其实,我们知道的互联网上的各种通信:网络请求、即时消息、文件传输和共享等基础都是通过套接字工具实现的,所以互联网都是套接字。 一旦理解了插座,你就通过任督二脉了。
2 .套接字的八个必需函数
插座并不可怕。 我们个人认为掌握以下几种c语言套接字函数就足够了。 1.intsocket (int域,int type,int protocol );
套接字函数对应于打开普通文件的操作。 常规打开文件操作返回文件描述符,但用于创建套接字(是唯一标识套接字的套接字描述符) socket descriptor。 该套接字描述符和文档描述符一样,也用于后续的操作,将其作为参数,通过它进行读写操作。
可以打开不同的文件,就像传递给fopen的不同参数值一样。 创建套接字时,也可以指定不同的参数来创建不同的套接字描述符。 socket函数的三个参数和return分别如下:
域(协议域,也称为协议族(family ) )。 通常,我们只要关心这两个协议族,AF_INET、AF_INET6就足够了。 AF_INET表示创建IPv4的套接字,AF_INET6表示创建IPv6的套接字。
类型:指定套接字类型。 有常用的套接字类型。 通常,只关心SOCK_STREAM、SOCK_DGRAM这两种类型就足够了。 SOCK_STREAM表示TCP类型的socket,SOCK_DGRAM表示UDP类型的socket。
protocol :旧名的意思是指定协议。 经常使用的协议是IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,分别是TCP传输协议、UDP传输协议、STCP传输协议通常,记住将此参数设置为0就足够了。 如果协议为0,则自动选择与类型对应的默认协议。
return :设置接口描述符。 如果发生错误,则返回-1,并将errno设置为适当的值
调用套接字创建套接字时,返回的套接字描述符存在于协议系列(address family,AF_XXX )空间中,但没有特定的地址。 要分配地址,必须调用bind (函数。 否则,在调用connect )、listen ) )时会自动随机分配端口。 具体说明如下。 2.intbind(intsockfd,const struct sockaddr *addr,socklen_t addrlen );
如上所述,bind ) )函数为套接字分配地址族中的特定地址(IP端口)。 例如,与AF_INET、AF_INET6相对应的是为套接字分配一个ipv4或ipv6地址和端口号组合。 必须将端口号指定为服务端。 如果不指定,客户端将不知道应该连接到哪个端口。 因此,服务器通常需要初始化并绑定到套接字)调用函数以绑定地址(listen ) )。 客户端通常可以初始化套接字,并在知道服务器的IP地址和端口号时直接调用connect )函数进行连接。 你不需要绑定自己的地址。 这是因为系统随机分配给客户机的地址(IP端口)已经隐式发送到服务器。 好了,说了这么多,我来说三个参数和return的意思吧:
sockfd:socket描述符,由socket ()函数创建,用于唯一标识socket。 bind ) )函数是
将给这个描述字绑定一个名字。
addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,如ipv4对应的是:struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
addrlen:对应的是地址的长度。
return:成功返回0,失败返回-13. int listen(int sockfd, int backlog);
作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
sockfd:即为要监听的socket描述字
backlog:相应socket可以排队的最大连接个数。
return:成功返回0,失败返回-14. int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
作为客户端初始化完socket,不需要bind()就直接可以connect()与服务端建立连接了。因为系统会自动生成一个随机的地址(具体应该为本机IP+随机端口号)。
sockfd:还没绑定客户端具体地址的socket描述字
addr:即将要连接到服务端的地址(IP+port)
addrlen:地址长度
return:如果是阻塞连接,成功立即返回0,如果失败,在iOS系统上超时大约一分钟后返回-15. int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,并把会这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。
sockfd:已经绑定具体服务端地址的socket描述字。
sockaddr:一般为NULL,这个参数可以理解为interface指定连接必须从哪里来的,比如是localhost、wifi还是以太网卡。NULL为任意方式。
addrlen:sockaddr地址长度
return:成功返回服务器端socket描述字否则错误。6. ssize_t write(int fd, const void *buf, size_t count);
服务端与客户端建立了通信接下来就可以实现网络通信了,可以调用网络I/O进行读写操作了,即实现了网络中不同进程之间的通信!
fd:要写入的的socket文件描述符
buf:将要被写入的缓冲区数据
count:被写入的数据长度
return:返回值大于0,表示写了部分数据或者是全部的数据,这样用一个while循环不断的写入数据,但是循环过程中的buf参数和count参数是我们自己来更新的,也就是说,网络编程中写函数是不负责将全部数据写完之后再返回的,说不定中途就返回了!返回值小于0表示出错。代码见第三部分7. ssize_t read(int fd, void *buf, size_t count);
如果系统事件源有了一个读取信号事件发生,那么我们可以调用read方法读取网络I/O中的数据。
fd:建立连接的socket文件描述符
buf:读取数据后放入的缓冲区
count:缓冲区大小
return:当读取成功时,read返回实际读取到的字节数,这样我们可以用一个while循环不断的读取数据,但是循环过程中的buf参数和count参数是我们自己来更新的,也就是说,网络编程中写函数是不负责将全部数据读取完之后再返回的。如果返回值是0,表示已经读取到文件的结束了,小于0表示是读取错误。代码见第三部分8. int close(int fd);
在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。
三.循环读取和写入代码循环写入代码
循环读取代码