TCP是数据的介质,Socket是TCP的介质。
一篇对tcp和socket关系讲解挺形象的博客 点这里
还有一篇 点这里 带图很细!
Socket是什么呢?
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
一般来说,socket编程基本就是listen,accept以及send,write等几个函数,和开文件流读写文件一个感觉,实际上并不清楚具体关系。实际上,下面引用:
TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。就像操作系统会提供标准的编程接口,比如Win32编程接口一样,TCP/IP也必须对外提供编程接口,这就是Socket编程接口。
在Socket编程接口里,设计者提出了一个很重要的概念,那就是socket。这个socket跟文件句柄很相似,实际上在BSD系统里就是跟文件句柄一样存放在一样的进程句柄表里。这个socket其实是一个序号,表示其在句柄表中的位置。这一点,我们已经见过很多了,比如文件句柄,窗口句柄等等。这些句柄,其实是代表了系统中的某些特定的对象,用于在各种函数中作为参数传入,以对特定的对象进行操作--这其实是C语言的问题,在C++语言里,这个句柄其实就是this指针,实际就是对象指针啦。
socket跟TCP/IP并没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以,socket的出现只是可以更方便的使用TCP/IP协议栈而已,其对TCP/IP进行了抽象,形成了几个最基本的函数接口。比如create,listen,accept,connect,read和write等等。
Linux系统是通过提供套接字(socket)来进行网络编程的。网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符。socket也有一个类似于打开文件的函数:socket(),调用socket(),该函数返回一个整型的socket的描述符,随后的连接建立、数据传输等操作也都是通过该socket实现。
然后就是具体的交互流程:
服务器
1、创建socket
int socket(int domain, int type, int protocol);
功能说明:
调用成功,返回socket文件描述符;失败,返回-1,并设置errno
参数说明:
- domain:AF_INET、AF_INET6、AF_UNIX,
AF
的释义就address family
,地址族的意思,我们常用的有 ipv4、ipv6 - type: SOCK_STREAM、SOCK_DGRAM等,最常用的就是
SOCK_STREAM
,基于字节流的SOCKET类型,也是TCP协议使用 的类型 - protocol: SOL_TCP、SOL_UDP 这个就是具体使用的传输协议,一般可靠的传输我们选择 TCP,游戏数据传输我们一般选 用 UDP 协议 。 为0时自动选择type默认协议。
2、绑定socket和端口号
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能说明:
将套接字和指定的端口相连。成功返回0,否则,返回-1,并置errno.
参数说明:
sock_fd:调用socket函数返回值, 即 套接字描述符
addr:一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
struct sockaddr_in:结构类型是用来保存socket信息的:
// IPv4的sockaddr地址结构
struct sockaddr_in {
sa_family_t sin_family; // 协议类型,AF_INET
in_port_t sin_port; // 端口号
struct in_addr sin_addr; // IP地址
};
struct in_addr {
uint32_t s_addr;
}
3、监听端口号
int listen(int sockfd, int backlog);
功能说明:
等待指定的端口的出现客户端连接。调用成功返回0,否则,返回-1,并置errno.
参数说明:
sockfd:要监听的sock描述字。
backlog:socket可以排队的最大连接数。
4、接收用户请求
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能说明:
用于接受客户端的服务请求,成功返回新的套接字描述符,失败返回-1,并置errno。
参数说明:
sockfd:服务器socket描述字。
addr:指向地址结构指针。
addrlen:协议地址长度。
5、从socket中读取字符
ssize_t read(int fd, void *buf, size_t count);
功能说明:
read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0 表示出现了错误.
如果错误为EINTR说明读是由中断引起的,
如果错误是ECONNREST表示网络连接出了问题。
参数说明:
fd:连接描述字。
buf:缓冲区buf。
count:缓冲区长度。
6、关闭socket
int close(int fd);
功能说明:
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:
函数运行成功返回0,否则返回-1。
参数说明:
fd:同服务器端fd。
客户端
1、创建socket
int socket(int domain, int type, int protocol);
2、连接指定计算机
int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen);
功能说明:
客户端发送服务请求。成功返回0,否则返回-1,并置errno。
参数说明:
sockfd:客户端的sock描述字。
addr:服务器的地址。
addrlen:socket地址长度。
3、向socket写入信息
ssize_t write(int fd, const void *buf, size_t count);
功能说明:
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量。
参数说明:
fd、buf、count:同read中意义。
4、关闭socket
int close(int fd);
以下,截图自牛客c++面试宝典,侵删: