天天看点

TCP/IP网络编程学习(4):实现基于TCP的服务端/客户端# TCP服务端默认调用顺序

# TCP服务端默认调用顺序

  1. socket()

    : 创建套接字
  2. bind()

    : 分配套接字的地址
  3. listen()

    : 等待连接请求状态
  4. accept()

    : 允许连接
  5. read()/write()

    : 交换数据
  6. close()

    : 关闭连接

我们已调用

bind

函数给套接字分配了地址,接下来就要通过调用

listen

函数进入等待连接请求状态 。 只有调用了listen函数,客户端可发出连接请求。换言之,这时客户端才能调用

connect

函数(若提前调用将发生错误)。

#include <sys/socket.h>
int listen(int sock, int backlog);
//成功时返回 0 ,失败时返回-1
//sock 希望进入等待连接请求状态的套接字文件描述符,传递的描述符套接字参数成为服务器端套接字(监听套接字) 。
//backlog 连接请求等待队列( Queue )的长度,若为5 ,则队列长度为 5 ,表示最多使5个连接请求进入队列 。
           
服务器端处于

等待连接请求状态

是指,客户端请求连接时,受理连接前一直使请求处于等待状态 。
TCP/IP网络编程学习(4):实现基于TCP的服务端/客户端# TCP服务端默认调用顺序

服务端处于

等待连接请求状态

时,客户端的所有连接请求信息都通过套接字连接到服务端的

连接请求等待队列

上。

受理客户端连接请求

连接请求等待队列

上有请求时,服务端就进行受理,进入可接受数据的状态。服务器端创建的套接字用来接受客户端的连接请求。当调用

accept()

函数后自动创建套接字用于连接到客户端进行数据传输。如果队列中没有请求,

accept()

函数将阻塞到有请求。

#include <sys/socket.h>
int accept(int sock, struct sockaddr '* addr, socklen_t * addrlen);
// 成功时返回创建的套接字文件描述符,失败时返回-1
//sock: 服务器套接字的文件描述符。
//addr: 保存发起连接请求的客户端地址信息的变量地址值,调用函数后向传递来的地址充客户端地址信息。
//addrlen: 第二个参数addr结构体的长度量, 但是存有长度的变量地址。函数调用完成后,该变量即被填入客户端地址长度。
           

accept

函数受理连接请求等待 队列中待处理的客户端连接请求 。 函数调用成功时

accept

函数内部将产生用于数据I/O的套接字并返回其文件描述符。需要强调的是,套接字是自动创建的,并自动与发起连接请求的客户端建立连接 。

TCP/IP网络编程学习(4):实现基于TCP的服务端/客户端# TCP服务端默认调用顺序

客户端的调用顺序

  1. socket()

    :创建套接字
  2. connect()

    :请求连接
  3. read()/write()

    :交换数据
  4. close()

    :断开连接
#include <sys/socket.h>
int connect(int sock , struct sockaddr * servaddr, socklen_t addrlen);
//成功时返回 0 ,失败时返回-1
//sock: 客户端套接字文件描述符。
//servaddr: 保存目标服务器端地址信息的变量地址值
//addrlen: 以字节为单位传递已传递给第二个结构体参数servaddr的地址变量长度。
           

服务器端接受连接将连接放入

连接请求等待队列

TCP/IP网络编程学习(4):实现基于TCP的服务端/客户端# TCP服务端默认调用顺序

基于 TCP 的服务器端/客户端函数调用关系

服务器端创建套接字后连续调用

bind

listen

函数进入等待状态,客户端通过调用

connect

函数发起连接请求。需要注意的是,客户端只能等到服务器端调用

listen

函数后才能调

connect

函数。同时要清楚,客户端调用

connect

函数前,服务器端有可能率先调用

accept

函数 。当然,此时服务器端在调用

accept

函数时进入阻塞 ( blocking ) 状态, 直到客户端调

connect

函数为止 。

TCP/IP网络编程学习(4):实现基于TCP的服务端/客户端# TCP服务端默认调用顺序

实现迭代服务器端/客户端

编写回声(echo)服务端、客户端。服务器将客户端收到的字符串数据原封不动的传回客户端。

服务器端在同一时刻只与一个客户端相连,并提供回声服务 。

服务器端依次向 5个客户端提供服务并退出 。

客户端接收用户输入的字符串并发送到服务器端 。

服务器端将接收的字符串数据传 回客户端,即"回声 " 。

服务器端与客户端之间的字符串回声一直执行到客户端输入Q为止 。

服务器端代码:

for(i=0; i<5; i++){
	//每一次服务一个客户端,上一个关闭后阻塞到下一个客户端连接
	clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
	if(clnt_sock==-1)
		error_handling("accept() error");
	else
		printf("Connected client %d \n", i+1);
	//读取客户端发过来的信息
	while((str_len=read(clnt_sock, message, BUF_SIZE))!=0)
		write(clnt_sock, message, str_len);//将信息写回客户端,直到客户端关闭
	close(clnt_sock);//关闭与该客户端连接的套接字。
}
           

客户端代码:

while(1) //循环读取用户输入的数据
{
	fputs("Input message(Q to quit): ", stdout);
	fgets(message, BUF_SIZE, stdin);
	
	if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
		break;

	write(sock, message, strlen(message));
	str_len=read(sock, message, BUF_SIZE-1);
	message[str_len]=0;
	printf("Message from server: %s", message);
}
close(sock)