有些同学可能没有完成上一节留下的任务。所以,还是有必要在浏览一下整个程序的结构,不然大家可能看看文章也就过去了。
如果你还没有 git clone,赶紧的把下面命令输入到你的机器中执行。
git clone https://git.oschina.net/ivan_allen/unp.git
1. 文件浏览
图1 相关文件
目前在 unp/program
下,有一个 echo (回射服务器)文件夹,它下面存的全是不同的回射服务器程序,basic 表示最基本的,最简单的版本,其它的像 concurrent_server 表示支持并发的版本。
include 文件夹存的是公共头文件,util/common.cc 是一些预先封装好的函数,它可以简化我们的工作。里面包含的一些函数的基本功能在上一篇文章都已经解释过了。
2. echo 服务器
我们第一个学习的 echo 服务器位于 unp/program/echo/basic
下面。
echo 服务器,中文名叫回射服务器,它的意思是将接收来的数据原封不动的发送回去。但是为了体现出数据的区别,我在这里做了小小的改动,服务器接收到数据后,将所有字母转换成大写发送回去。这里用图 2 来描述 echo 服务器与客户端的关系。
图2 简单的回射服务器与客户端
下面给出 echo.cc 的伪代码,可以看到即使是伪代码,内容也非常多,但是大家抓住重点就好了。
2.1 echo.cc 代码结构
// 省去无关细节
int main() {
// 首先根据命令行参数判断是以服务器方式启动还是以客户端方式启动
if (isServer) {
server_routine();
}
else {
client_routine();
}
}
2.2 server_routine 服务器处理程序
void server_routine() {
listenfd = socket(tcp);
// 创建套接字地址
servaddr = resolve(hostname, port);
bind(listenfd, servaddr);
listen(listenfd);
sockfd = accept(listenfd);
// do_server 中处理 IO
do_server(sockfd);
close(sockfd);
}
do_server(int sockfd) {
while(1) {
// 从套接字读一行数据
n = readline(sockfd, buf);
// 如果等于 0 表示对端关闭。
if (n == 0) break;
// 将 buf 中的数据转换成大写
toUpper(buf);
// 发送给对方
writen(sockfd, buf, n);
}
}
2.3 client_routine 客户端处理程序
void client_routine() {
sockfd = socket(tcp);
servaddr = resolve(hostname, port);
// 连接服务器
connect(sockfd, servaddr);
doClient(sockfd);
close(sockfd);
}
doClient(int sockfd) {
// 从标准输入读一行
while(fgets(buf, stdin)) {
// 发送给服务器
writen(sockfd, buf, strlen(buf));
// 从服务器接收数据
n = readline(sockfd, buf);
// 如果 n == 0 表示对端关闭
if (n == 0) break;
}
}
3. 程序运行
3.1 网络拓扑
图3 我的实验环境
图 3 简单的画出了我实验所用的几台主机,主要有三台,分别是 sun 主机,flower 主机和 moon 主机。其它无关的设备就没在图上画了。
如果你不知道怎么配这个实验环境,请加群交流 610441700,记得注明你的来意,否则会被拒绝。
3.2 程序运行
- 服务器
// -s 表示以服务器方式启动,没写端口,默认是 8000 端口,sun 是我的主机名,可以配置在 /etc/hosts 文件中。
$ ./echo -s -h sun
- 客户端
// 没有指定 -s 选项,表示以客户端方式启动,默认连接 8000 端口
// 将 Makefile 定向到 echo 的标准输入
$ ./echo -h sun < Makefile
图4 左侧是服务器,右侧是客户端
4. 总结
- 一定要 git clone 下来读代码,切记!!!
- 掌握 TCP 服务器创建的基本流程,即先 bind 再 listen,然后 accept,这里的具体细节请参考《Linux 环境编程学习笔记》的第十四章网络编程基础。
思考1:没有 bind 行不行?
思考2:没有 listen 行不行?
思考3:将 echo 中的代码与三次握手协议对应起来,具体请参考《TCP 协议(建立连接)》、《接受连接》以及《发起连接请求》。(实际上我希望这三篇文章你都已经看过)
思考4:将 echo 中的代码与四次挥手协议对应起来,具体参考《TCP 协议(断开连接)》,一定要好好读!
最后,这一讲的内容够你研究个一天两天了,千万别试图半个小时或者一小时学会它!!!(有经验者无视)最后切记——勿在浮沙筑高台。
欢迎入群交流 610441700,记得注明你的来意,否则会被拒绝。