TCP服务端/客户端
TCP与UDP
TCP与UDP是传输层常见的网络协议。TCP/IP协议栈如图:
最底层为数据链路层,往上是IP层,再通过TCP或UDP到达应用层。
链路层负责点到点的传输,而IP层负责端到端的传输。但IP协议是不可靠的协议,数据丢失或者错误的情况无法解决。于是TCP就负责数据传输的可靠性。收到后确认,需要则重传。
应用层
我们所说的socket编程,其实都是发生在应用层的,大部分内容是设计和实现应用层的协议,上面的细节由socket自动处理。
TCP服务端的调用顺序为:
- socket()创建套接字
- bind()分配IP地址和端口号
- listen()等待连接请求
- accept()允许连接
- read()/write()数据交换
- close()断开连接
服务端:等待连接请求
在调用了listen()之后,客户端才可以调用connect()(想要建立连接先要接起电话)
#include <sys/socket.h>
int listen (int sock,int backlog);
第一个参数接收进入等待连接请求状态的套接字文件描述符(可以理解为编号),第二个参数是等待连接队列的长度。
可以理解为listen会生成一个门卫(服务端套接字),并设定等候室的大小,让请求的连接进入等候室。
服务端:允许连接
当有了新的请求时,需要新的套接字来进入这种状态,这时需要accept函数。
#include <sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen)
accept生成一个用于数据I/O的套接字,返回其文件描述符sockfd。第二个参数用于保存客户端地址信息。第三个参数用于保存客户端地址的长度。
简单来说就是从等待队列中取出一个连接请求,创建套接字然后完成连接。
客户端:请求连接
客户端请求连接时调用的是connect函数。
#include <sys/socket.h>
int connect(int sockfd,struct sockaddr *servaddr,socklen_t addrlen);
在服务端接收连接请求后,或者中断连接请求后,connect函数会返回。(接收连接不是accept,是进入到了服务端的请求队列)
服务端没有bind的过程。在调用connect函数时自动分配。
客户端与服务端的关系是:
回声服务器
回声的意思就是把服务端将客户端传来的字符数据再原封不动的传回去。
我们之前的模式都是处理完一个客户端请求就退出服务端。如果想要连续服务就需要用循环调用accept。
(如果想要同时服务多个客户端需要学习进程与线程)
我们来看回声服务器的核心代码:
int main(int argc,char* argv[])
{
int serv_sock,clnt_sock;//服务端和客户端的文件描述符
char message[BUF_SIZE];
int strlen,i;