面试的时候面试官问到“请问你是否了解socket编程?”
说实话,我是知道一些函数的,但是具体的实现我不了解,并且工作中也基本上没用到。所以我回答了“不是很了解,只是校招的时候知道一些函数”,现在想想,还是自己学习的不够系统,漏洞百出啊。
今天,简简单单学习下socket编程。
1.什么是socket编程?
socket是一种网络通信的技术。
上一篇博客复习了三次握手和四次挥手,但是没有复习到五大层及其所拥有的一些常见的协议。现在举例说明几个协议。
层级 | 协议 |
---|---|
应用层 | HTTP/FTP/DNS/SMTP |
传输层 | TCP/UDP |
网络层 | IP/ICMP/ARP |
数据链路层 | ARP/RARP |
物理层 |
五层架构展示完了,此时,就想socket通信,是在哪一层上或者哪一层和哪一层之间呢。
从博客
处摘要了该博主一张很生动的结构图:
很明显,socket通信位于应用层和传输层之间。流程大致为:传输层为socket层提供服务,socket层再为应用层提供服务。之前复习过了TCP三次握手,socket通信也是通过类似三次握手的形式实现的通信,现在直接看socket层是如何实现的吧。仍然是从上面博主的博客中得到这样一张简明扼要的结构图
这个三次握手的过程实质上时已经创建了socket通道之后的数据传输的过程,在这之前我们需要创建socket,并且利用socket中提供的方法来实现客户端和服务器之间的通信。
流程图:来自于博客
看一下socket各个函数的功能及使用。
//不要忘记包含头文件
1.socket()函数
#include <WinSock2.h>
/*
param domain 协议族,如AF_INET,AF_INET6等
param type 指定socket(套接口)类型,如SOCK_STREAM,SOCK_DGRAM
param protocol 指定协议(一般为0,根据type有默认值),如IPPROTO_TCP,IPPROTO_UDP等
*/
int socket(int domain, int type, int protocol);
2.bind函数
#include <WinSock2.h>
/*
sockfd socket()函数的返回值
address 指向特定协议的地址结构指针
addLen address所指向的结构体的长度
*/
int bind(int sockfd, const struct sockaddr* address, socklen_t addLen);
3.listen()函数
该函数只在TCP服务器中使用,和客户端无关。
#include <WinSock2.h>
/*
sockfd 当前创建的套接口的标识
backlog 后台等待连续队列的最大限制值
*/
int listen(int sockfd, int backlog);
4.connect()函数
该函数有客户端调用,和服务器建立连接
#include <WinSock2.h>
/*
sockfd 客户端创建的套接口标识
addr 指向套接口地址结构的指针
addrlen addr指向结构体的大小
*/
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
5.accept()函数
该函数由TCP服务器调用
#include <WinSock2.h>
/*
sockfd 服务器 创建的套接口标识
addr 返回客户端的协议地址
addrlen 协议地址的长度
*/
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
6.close()函数
close函数用于关闭套接口,服务器端和客户端均调用。
#include <WinSock2.h>
//sockfd 套接口的标识
int close(int sockfd);
客户端和服务器建立了通信之后。此时我们就可以把socket的返回值(sockfd)当做文件描述符来使用。
今天补充两个重要的函数,也是面试的时候问到的函数。
1.write函数
//write将缓存buf中的bytes个字节大小的写入sockfd,成功时候返回写的字节数大小,失败时-1.
size_t write(int sockfd, void* buf, size_t bytes)
//返回值大于0时,表示写了部分或者全部数据。
//小于0 时表示出错。
2.read函数
size_t read(int fd,void *buf,size_t nbyte)
//从fd中读取内容.
//返回值大于0时,表明实际所读的字节数
//返回值为0,表示已经读到文件的结束了,
//返回值小于0,表示出现了错误。如果错误为EINTR说明读是由中断引起 的, 如果是ECONNREST表示网络连接出了问题.
当然,还有recv和send函数用于读写操作。