Chap.5 基于TCP的服务器端/客户端(2)

已知字符串长度情况下完善回声客户端

# gcc echo_client2.c -o eclient2
# ./eclient2 127.0.0.1 9190
Connected
Input message (Q to quit): orange
Message from server: orange
Input message (Q to quit): hhhhhhhhhhhhhhhhhhhhhhhhhhhh
Message from server: hhhhhhhhhhhhhhhhhhhhhhhhhhhh
Input message (Q to quit): q

服务端同上一章。


定义应用层协议

原书中有些bug,服务端接收到的操作数个数没有转换成int。经fix后代码见附录,运行结果如下:

# ./opserver 9190
Connected client 1 
Connected client 2 
Connected client 3 
# ./opclient 127.0.0.1 9190
Connected
Input operand count: 3
Input operand: 1
Input operand: 5
Input operand: 9
Input operator: +
Operation result: 15
# ./opclient 127.0.0.1 9190
Connected
Input operand count: 4
Input operand: 16
Input operand: 8
Input operand: 4
Input operand: 2
Input operator: -
Operation result: 2
# ./opclient 127.0.0.1 9190
Connected
Input operand count: 2
Input operand: 5
Input operand: 7
Input operator: *
Operation result: 35


TCP原理

I/O缓冲特性:

  • I/O缓冲在每个TCP套接字中单独存在。
  • I/O缓冲在创建套接字时自动生成。
  • 即使关闭套接字也会继续传递输出缓冲区中的遗留数据。
  • 关闭套接字将丢失输入缓冲区中的遗留数据。


习题

  1. 请说明TCP套接字连接设置的三次握手过程。尤其是3次数据交换过程每次收发的数据内容。
    1)A向B发起连接,发送SYN包(SYN=1,seg=X)
    2)B回复SYN_ACK包(SYN=1,ACK=1,seg=Y,ack number=X+1)
    3)最后A向B传输消息(ACK=1,seg=X+1,ack number=Y+1)
    从步骤3)开始A就可以携带应用层数据了。
  2. TCP是可靠的数据传输协议,但在通过网络通信的过程中可能丢失数据。请通过ACK和SEQ说明TCP通过何种机制保证丢失数据的可靠传输。
    SEQ是当前数据起始字节的序号,加入收到对方返回的ACK刚好是SEQ+数据大小(以字节为单位),则代表正确送达,可以继续发送后续数据包。反之,在计时器超时后进行重传。
  3. TCP套接字中调用write和read函数时数据如何移动?结合I/O缓冲进行说明。
    write函数调用瞬间,数据将移至输出缓冲;read函数调用瞬间,从输入缓冲读取数据。
  4. 对方主机的输入缓冲剩余50字节空间时,若本方主机通过write函数请求传输70 字节,请问TCP如何处理这种情况?
    将70字节数据放入输出缓冲,然后发送50字节到对方主机,待对方主机的输入缓冲又有剩余时再发送后面的字节。
  5. 第2章示例tcp_server.c和tcp_client.c中,客户端接收服务器端传输的字符串后便退出。现更改程序,使服务器端和客户端各传递1次字符串。考虑到使用TCP协议,所以传递字符串前先以4字节整数型方式传递字符串长度。连接时服务器端和客户端数据传输格式如下。另外,不限制字符串传输顺序及种类,但须进行3次数据交换。
    代码见附录。
    0   0   0   6   H   e   l   l   o   ?
   |-- 字符串长度 --|------ 字符串数据 ------|
# gcc tri_server.c -o tserver
# ./tserver 9191
Connected client 1 
Message from client: Hello?
Input message: Hi!
Message from client: This is Xiao.
Input message: I'm Yao.
Message from client: Nice to meet you!
Input message: Me, too.
# gcc tri_client.c -o tclient
# ./tclient 127.0.0.1 9191
Connected
Input message: Hello?
Message from server: Hi!
Input message: This is Xiao.
Message from server: I'm Yao.
Input message: Nice to meet you!   
Message from server: Me, too.
  1. 创建收发文件的服务器端/客户端,实现顺序如下。
    a. 客户端接受用户输入的传输文件名。
    b. 客户端请求服务器端传输该文件名所指文件。
    c. 如果指定文件存在,服务器端就将其发送给客户端;反之,则断开连接。
    代码见附录。
# gcc file_server.c -o fserver
# ./fserver 9190
Connected client
# gcc file_client.c -o fclient
# ./fclient 127.0.0.1 9190
Connected
Input file name: exercise6


我的问题

  1. 把int存到char型数组中后发生了什么?
  2. fgetc(stdin)的作用?
    删除stdin中的"\n"字符,因为前面读取操作数的时候,最后有一个回车,他不能被当做运算符读进来。而前面读操作数之前为什么不fgetc一下呢?因为读取的是%d,它会自动找到整数来读取,忽略先导的空白符(指空格符、制表符、回车符)。但当读取的是%c的时候,scanf把缓冲区的第一个字符返回回去,不管是什么,所以如果不fgetc就会读取出“\n”。
  3. seq与ack number的关系?
    书中的seq与ack number有错误。以图5-4为例进行改正。
A                                           B
|    --- seq 1200 (100 bytes data) -->      |
|         <-- ack number 1300 ---           |
|    --- seq 1300 (100 bytes data) -->      |
|         <-- ack number 1400 ---           |
  1. C语言如果不初始化局部整型变量,里面的值是什么?
    与编译器有关。对GCC来说,局部整型变量里的值是随机的。所以初始化是必需的。
  2. 为什么要用fgets读取用户输入,而不是scanf?
    scanf遇空白符(空格、回车、制表符)即终止读取,无法一次性读取完整的一个句子。而fgets每次读取一行。


附录

[1] 关于int整数转换存储到字符数组
[2] scanf用法及scanf中有\n的问题
[3] TCP连接建立的三次握手过程可以携带数据吗?
[4] Github

你可能感兴趣的:( Chap.5 基于TCP的服务器端/客户端(2))