TCP IP Socket In C, 2e - chapter 2 Basic TCP Socket

本章以TCP,即Stream Socket写一个echo程序。

其实本章可以参考我的另一篇,就足够了:Socke编程简介
至于Socket的API函数可以参考:Linux下C Socket编程基础API


1. IPv4 TCP Client

向Server发起通信请求,Server是被动等待连接的。

第一个程序,echo客户端程序:TCPEchoClient4.c。这个程序还引入了另一个工具头文件:Practical.h,其中使用到的函数实现在DieWithMessage.c。在两个DieWithXxx函数中,为什么使用fputs(),而非printf(),是因为把从网络接收的数据作为第一个参数传递给printf()有安全漏洞,至于是什么安全漏洞我还不晓得,查了下有关printf格式化漏洞的,请参见*printf()格式化串安全漏洞分析(上)

客户端工作步骤:

  1. 使用socket()创建一个TCP Socket;
  2. 使用connnect()向Server建立连接;
  3. 使用send()recv()进行通信;
  4. 使用close()关闭连接。

一般在基础的Socket编程中使用的头文件如下所列:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>

上述所说以及所用的函数原型可以通过Man Pages查到,查询命令:man <functionName>


2. IPv4 TCP Server

C/S结构肯定是一对的,有客户端和服务器端。很多系统都有一个echo服务器用来调试(debugging)和测试(testing),但是因为安全的原因,这些服务器经常是不可用的。

这里给出echo服务器端程序代码:TCPEchoServer4.c。在这里它还调用了Practical.h中另外一个函数HandleTCPClient(),不过该文件不止这一个函数,编译的话,还需要和另外一个文件AddressUtility.c一起编译,或者先注释掉其它函数。

服务器端工作步骤:

  1. 使用socket()创建一个TCP socket;
  2. 使用bind()给socket分配一个端口号;
  3. 使用listen()告知系统允许使用上述端口的连接;
  4. 重复:
    • 对每一个客户端连接调用accept()获取一个新的socket
    • 使用send()recv()和客户端进行通信;
    • 使用close()关闭客户端连接。

看服务器端和客户端的工作步骤就知道了,服务器端比客户端多了bind()以及listen()accept()

2.1 设置socket

其实connect()也会绑定端口,不过用户不在乎这个端口是哪个罢了,端口的分类与分配可以参考Service Name and Transport Protocol Port Number Registry

bind()这里还有一个需要注意的,就是它使用了

servAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface

这个设置使得服务器可以不需要任何一个实质性的IP地址以接受客户端连接。

bind()失败的原因很多,一个主要原因是其它socket正在使用这个端口号以及一些端口号(如系统端口号1~1023)的使用需要权限。

listen()就是监听bind()绑定的端口号,后一个参数表示,最多能够处理的连接数量(参考listen()的注释:N connection requests will be queued before further requests are refused.)

2.2 处理收到的连接

在这里使用了无限循环。

accept()是一个阻塞方法,挂起等待直到客户端发来连接请求,如果有了请求它会返回一个新的socket文件描述符,此时已经和远端(客户端)socket建立了连接。这样就表示可以收发信息了,不过需要使用新的socket文件描述符。

2.3 注意事项

在编译运行该程序的时候,需要注意,虽然客户端程序port参数默认给的是7,但是实际上取决于你给服务器端设置的port参数。如果你要是把服务器端的端口设置为7,就可能会出现在2.1节所说问题:bind() failed: Permission denied。所以一定要保证二者段口一致且别用系统端口。

Socket编程的一个重要原则是防卫式编程(Defensive Programming):就是说你的代码不能信任从网络上收到的任何信息!

作为自己写客户端的替代,你可以使用telnet程序。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章