本章以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()格式化串安全漏洞分析(上)。
客户端工作步骤:
- 使用
socket()创建一个TCP Socket; - 使用
connnect()向Server建立连接; - 使用
send()和recv()进行通信; - 使用
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一起编译,或者先注释掉其它函数。
服务器端工作步骤:
- 使用
socket()创建一个TCP socket; - 使用
bind()给socket分配一个端口号; - 使用
listen()告知系统允许使用上述端口的连接; - 重复:
- 对每一个客户端连接调用
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程序。
本文深入解析TCP Socket编程,包括客户端和服务端的实现流程,重点介绍了socket的创建、连接、通信及关闭过程。同时,探讨了bind、listen和accept等关键函数的作用及注意事项。
1726

被折叠的 条评论
为什么被折叠?



