linux&C这两天学到了网络编程这一章,自己写了一个小的”服务器”和”客户端”程序,目的在于简单理解tcp/ip模型,以及要搭建一台简单服务器,服务器和客户端最基本的事情要干什么,这篇博客就这个小程序,也简单分析了自己对”TCP-三次握手”过程的理解。因为初学网络编程,说的不对的地方欢迎大家评论交流。

套接字:
套接字由4部分组成,服务器IP地址和客户端IP地址以及服务器端口号和客户端端口号,是客户端和服务器端传输数据确定线路的保证,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

首先我们来看服务器端的代码:

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<sys/socket.h>
  4. #include<netinet/in.h>
  5. #include<arpa/inet.h>
  6. #include<unistd.h>
  7. #include<stdlib.h>
  8. #define MAX_QUEUE_LENGTH 1024
  9. int main(int argc,char *argv[])
  10. {
  11. int sock_fd,conn_fd;
  12. struct sockaddr_in serv_addr,conn_addr;
  13. socklen_t conn_len;
  14. pid_t pid1;
  15. char recv_buf[128];
  16. int ret;
  17. //创建套接字
  18. sock_fd = socket(AF_INET,SOCK_STREAM,0);
  19. /*参数分别为(使用IPV4 tcp/ip协议,使用tcp流套接字,
  20. 通过前两个参数来确定使用的协议类型,默认为零)*/
  21. //mZ服务器端的套接字进行初始化
  22. memset(&serv_addr,0,sizeof(struct sockaddr_in));
  23. //memset函数将serv_addr 用0进行初始化
  24. serv_addr.sin_family = AF_INET;
  25. /*设置地址类型:对于sin_family,表示用tcp/ip协议编程,
  26. 所以此值只能为AF_INEF*/
  27. serv_addr.sin_port = htons(4507);
  28. //设置端口号为4507
  29. serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  30. //关于ANADDR——ANY这个宏的解释在下面有,也可以向下面一样设定指定IP
  31. //inet_pton(AF_INET,"XXX.XXX.XXX.XXX",&serv_addr.sin_addr);
  32. //当我只有一块网卡,一个IP,所以也只能设置为自己的ip了
  33. //绑定套接字
  34. bind(sock_fd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr_in));
  35. /*绑定套接字的过程是将我前面创建的套接字与初始化的端口绑定起来, 因为socket只是创建了一个套接字,这个套接字将在哪个端口上工作, 并没有被指定,作为服务器,它的IP和端口一般是固定的,因此我们需要将刚才
  36. 初始化的端口和套接字绑定到一起,这时套接字已经完成服务器的ip和端口这一半*/
  37. //将套接字转化成监听套接字
  38. listen(sock_fd,MAX_QUEUE_LENGTH);
  39. //第二个参数比较重要,它是我们服务器已完成套接字队列的长度,accept函数每次
  40. //会从已完成的套接字队列中拿走一个即conn_fd,也就是监听套接字,注意:内核会维护两个队列,
  41. //一个是已完成的套接字队列,一个是未完成的套接字队列,一个套接字完成的过程是在三次握手的
  42. //过程中完成的,是由tcp/ip协议栈完成的
  43. //接受客户端的请求
  44. conn_len = sizeof(struct sockaddr_in);
  45. while(1)
  46. {
  47. conn_fd = accept(sock_fd,(struct sockaddr *)&conn_addr,&conn_len);
  48. //服务器会将客户端的连接消息先放在未完成的队列中,三次握手之后,就到已完成队列中
  49. //conn_fd就是accept返回的叫作连接套接字,它的信息有服务器的端口和IP以及客户的端口和IP,
  50. //监听套接字继续监听,对于新的处理,系统会重新开一个线程处理,自己也可以用进程
  51. printf("accept a new connection,ip:%s\n",inet_ntoa(conn_addr.sin_addr));
  52. pid1 = fork();
  53. if(pid1 == 0)
  54. ret = recv(conn_fd,recv_buf,sizeof(recv_buf),0);
  55. recv_buf[ret-1] = '\0';
  56. }
  57. printf("%s\n",recv_buf);
  58. }

注释中解释了套接字的初始化,建立,绑定,监听的过程,结束之后我们服务器端的工作就做好了,为了检验程序是否正确,运行程序之后我们可以用netstat命令查看我们服务器端是否开启监听模式

$ netstat -apt | grep LISTEN


可以看到4507端口的状态是LISTEN。

在说说INADDR_ANY的作用

INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。举个例子:你的电脑上如果有多块网卡就会有好几个IP,或者说你的服务器有多台主机也会有好多个IP,而如果你的IP会发生变化,比如变多或者变少,但是为了减少bind()时的麻烦,可以统一设定就在0.0.0.0这个地址上监听。所有的信息都会到这个地址上,如果你需要将服务器上的所有IP中的80端口监听,再将80端口绑定就OK了,我就了解了这么多。

然后再看我们的客户端代码:

  1. #include<stdio.h>
  2. #include<sys/types.h>
  3. #include<unistd.h>
  4. #include<string.h>
  5. #include<stdlib.h>
  6. #include<arpa/inet.h>
  7. #include<netinet/in.h>
  8. int main(int argc,char *argv)
  9. {
  10. struct sockaddr_in serv_addr;
  11. int conn_fd;
  12. //同样我们需要在客户端也建立套接字
  13. conn_fd = socket(AF_INET,SOCK_STREAM,0);
  14. //初始化与服务器端匹配的信息
  15. memset(&serv_addr,0,sizeof(struct sockaddr_in));
  16. serv_addr.sin_family = AF_INET;
  17. serv_addr.sin_port = htons(4507);
  18. inet_aton("192.168.20.144",&serv_addr.sin_addr);
  19. //用于向服务器端发送连接请求,服务器的IP地址和端口号由参数serv_addr指定
  20. connect(conn_fd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr_in));
  21. close(conn_fd);
  22. }

客户端有点简单啊,但是可以登录,这样就可以基本实现我们的客户端和服务器之间连接了,下面我们进入我们的主题:是不是都忘了我们的主题是——“三次握手“。
在这个实例中,三次握手发生在客户端执行connect函数的时候。三次握手的过程下面的图片可以显示清楚,我再举个例子

第一次 client->server SYN=1,seq = x
第二次 server->client SYN=1,ACK = 1,seq = y,ack = x+1
第三次 client->server ACK=1,seq = x+1
SYN:同步序号,当SYN=1,ACK=0时,表明这是一个连接请求。
ACK:当ACK=1时,确认号字段即ack才有效。
seq:范围:[0,2^32 - 1],表示发送的第一个字节的编号。
ack:确认号,当ack = n,表示到n-1为止的所有字节都已经被收到。

另外我用tcpdump命令抓了个包,可以分析下,不对的地方指出

$ tcpdump port 4507


我的客户端IP为192.168.122.172,服务器的IP为192.168.20.128
第一次:Flag[S],表示这是一个请求连接,S是SYN字母的首字母,seq是将要发送的首字节的序列号,此时SYN = 1,ACK = 0。
第二次:收到SYN = 1的包,将ACK置为1,ack = 1588197944表示在此之前的字节我已经全部收到。
第三次:当再次收到SYN=1,ACK=1的包时,将ack = 1,表示确认连接。

“TCP:三次握手”分析——以一个简单的“服务器”和“客户端”为例的更多相关文章

  1. Wireshark抓包介绍和TCP三次握手分析

    wireshark介绍 wireshark的官方下载网站: http://www.wireshark.org/ wireshark是非常流行的网络封包分析软件,功能十分强大.可以截取各种网络封包,显示 ...

  2. TCP三次握手四次分手—简单详解

    关于TCP三次握手四次分手,之前看资料解释的都很笼统,很多地方都不是很明白,所以很难记,前几天看的一个博客豁然开朗,可惜现在找不到了.现在把之前的疑惑总结起来,方便一下大家. 疑问一,上图传递过程中出 ...

  3. 用C++写一个简单的服务器和客户端

    我们将创建一个服务器节点add_two_ints_server,它将会收到两个整数,并且返回它们的和.切换目录到之前建立的beginner_tutorials包下: cd ~/catkin_ws/sr ...

  4. 抓包工具-Wireshark(详细介绍与TCP三次握手数据分析)

    功能使用的详细介绍 wireshark(官方下载网站: http://www.wireshark.org/),是用来获取网络数据封包,可以截取各种网络封包,显示网络封包的详细信息,包括http,TCP ...

  5. Wireshark抓包TCP三次握手数据

    抓包工具 - Wireshark(详细介绍与TCP三次握手数据分析) 功能使用的详细介绍 wireshark(官方下载网站: http://www.wireshark.org/),是用来获取网络数据封 ...

  6. 这次一定让你记住 TCP 三次握手、四手挥手!

    TCP协议全称为:Transmission Control Protocol,是一种面向链接.保证数据传输安全.可靠的数据传输协议.为了确保数据的可靠传输,不仅需要对发出的每个字节进行编号确认,还需要 ...

  7. 详解TCP三次握手(建立TCP连接过程)

    在讲述TCP三次握手,即建立TCP连接的过程之前,需要先介绍一下TCP协议的包结构. 这里只对涉及到三次握手过程的字段做解释 (1) 序号(Sequence number) 我们通过 TCP 协议将数 ...

  8. 简单说说TCP三次握手、四次挥手机制

    1.什么是TCP TCP全称Transmission Control Protocol(传输控制协议),是一种面向连接的.可靠的.基于字节流的传输层通信协议.是为了在不可靠的互联网络上提供可靠的端到端 ...

  9. 用tcpdump分析tcp三次握手,四次挥手

    1.tcpdump 简介 tcpdump是一个对网络上的数据包进行截获的包分析工具,一般linux系统以命令的形式使用 2.tcp三次握手 建立一个tcp连接会发生下面三个过程: 1.服务器必须准备好 ...

随机推荐

  1. JDBC-1(概述&建立)

    基于宋红康老师所讲JDBC所作笔记 1.JDBC概述 1.1 数据持久化 持久化:将数据保持到可掉电式存储设备中以供之后使用. 数据持久化意味着将内存中的数据保存到硬盘上加以固化,实现过程大多通过各种 ...

  2. 谷歌浏览器chrome安装插件报"程序包无效: CRX_HEADER_INVALID"错误

    今天参加需求评审,看到原来可以谷歌浏览器查看Axure原型文件,真是只有想不到,没有做不到(自己孤陋寡闻了,第一次接触Axure). 需求评审后,我百度"如何使用谷歌浏览器查看Axure原型 ...

  3. Fiddler修改抓包请求

    hi,说到fiddler的用途,第一时间想到抓包,不过还有一个功能是:支持修改请求. 那么问题来了,怎么做呢?很简单,先定下我们需要修改哪个请求. 这里用F12跟fiddler做演示. 首先我们在F1 ...

  4. 分享一个设计logo的网站

    https://editor.freelogodesign.org/

  5. supervisor + celery 的简单配置与报错处理

    ubuntu服务器下使用 supervisor 和 celery supervisor 的卸载过程: sudo apt purge supervisor whereis supervisord如果有用 ...

  6. AT4518-[AGC032C]Three Circuits【欧拉回路】

    正题 题目链接:https://www.luogu.com.cn/problem/AT4518 题目大意 给出\(n\)个点\(m\)条边的一张简单无向联通图,求能否把它分成三个可重复点的环. \(1 ...

  7. LaTeX Vscode 配置

    安装:https://www.latexstudio.net/archives/51801.html LaTeX 安装 & 宏包升级 & 入门:https://blog.csdn.ne ...

  8. PHP的SPL扩展库(一)数据结构

    SPL 库也叫做 PHP 标准库,主要就是用于解决典型问题的一组接口或类的集合.这些典型问题包括什么呢?比如我们今天要讲的数据结构,还有一些设计模式的实现,就像我们之前讲过的观察者模式相关的接口在 S ...

  9. dbus中的数据类型

    DBus中也是类似于静态语言,使用了"强类型"数据格式.在DBus上传递的所有数据都需要声明其对应的类型,下面整理了下,DBus中的数据类型,以及在DBus中声明的数据类型是什么意 ...

  10. 利用水文分析方法提取山脊线和山谷线(ArcPy实现)

    一.背景 作为地形特征线的山脊线.山谷线对地形.地貌具有一定的控制作用.它们与山顶点.谷底点以及鞍部点等一起构成了地形起伏变化的骨架结构.同时由于山脊线具有分水性,山谷线具有合水性特征,使得它们在地形 ...