环境:Linux  C
 
一、协议介绍
     TCP是面向连接的协议,提供可靠的数据传输;TCP协议的可靠传输基于三次握手、四次挥手以及确认重传机制实现。下面来具体展示下TCP的三次握手、四次挥手状态
    大家都知道已经建立连接的TCP遇到网络丢包会有确认重传机制。在三次握手期间,如果A收到B的SYN+ACK,但是B没有收到A返回的ACK,此时B超时后会重传SYN+ACK,如果超过特定次数依然没有收到A的ACK,那么B向A发送RST包,关闭连接,避免A维护一个异常的连接。四次挥手也是类似,都是利用超时重传机制。
 
二、TCP网络编程
     先展示一段代码

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h> int main(int argc, char *argv[])
{
int fd;
struct sockaddr_in addr;
struct timeval timeo = {3, 0};
//lingger参数1表示启用linger,5最多等待5秒或者socket发送队列中的消息发送完毕
//再执行close操作
struct linger linger_value = {1, 5};
socklen_t len = sizeof(timeo); //创建TCP连接,SOCK_CLOEXEC指明在执行fork等创建子进程函数时,子进程将继承的该fd描述符默认关闭
fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (argc == 4)
timeo.tv_sec = atoi(argv[3]); //设置接受socket数据的等待时间,对read,recv,recvfrom等函数生效
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len); //设置该参数是为了保证在关闭前尽可能的将数据都发送出去
setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger_value, (socklen_t)sizeof(linger_value)); addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2])); //connect受SO_SNDTIMEO设置影响,最多等待timeo时间
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
if (errno == EINPROGRESS) {
fprintf(stderr, "timeout\n");
return -1;
}
perror("connect");
return -1;
}
printf("connected\n"); char *msg = "hello buddy !";
//这里指定MSG_NOSIGNAL表示当fd已经关闭时,不会触发SIGPIPE信号(该信号的默认操作是关闭程序
send(fd, msg, strlen(msg), MSG_NOSIGNAL); char buffer[1024] = {'\0'};
//这里的MSG_DONTWAIT就是要求recv函数非阻塞执行 ,同给socket设置SO_NONBLOCK效果一样
recv(fd, buffer, sizeof(buffer) - 1, MSG_NOSIGNAL | MSG_DONTWAIT); //向对端发送FIN报文,关闭该fd上所有的读写socket连接
shutdown(SHUT_RDWR, fd); //关闭文件描述符,如果执行了fork函数且没有设置SOCK_CLOEXEC,需要在子进程中也执行close关闭继承的文件描述符
close(fd); return 0;
}

注:该代码是客户端的一部分代码,服务端与这个类似,区别就是服务端用bind、listen、accept函数替代了connect函数来实现对服务端口的监听、新连接的处理。

  1. 编写多进程程序时,如果创建文件描述符(打开文件、创建socket等)都需要设置SOCK_CLOEXEC标识,避免出现副作用。
  2. 给socket设置SO_LINGER选项、调用close之前执行shutdown命令一般用于服务端,这样可以最大限度地保证将数据发送到客户端并且可以有效防止,因为fork导致的子进程在处理socket时调用close关闭fd描述符,由于fd原有计数是2,所以fd并未实际关闭,也就不会触发向客户端发送FIN报文结束连接的动作。因而,服务端就可能出现大量的CLOSE_WAIT的连接。
  3. 如果系统收到FIN报文,会让recv、read等函数返回0表示连接已经关闭。此时send、recv等读写函数再对目标fd进行读写,根据TCP协议规定,会收到一个RST报文,如果再读写的话系统就会发送SIGPIPE信号给调用进程,而该信号默认动作是结束进程。因此,要么调用信号处理函数将SIGPIPE捕获处理,要么像代码中那样设置MSG_NOSIGNAL选项避免产生SIGPIPE信号。
  4. SO_SNDTIMEO除了对send、write等有效外,还对connect有效;SO_RCVTIMEO除了对recv、read等有效外还对accept有效。
  5. 如果系统中出现大量的close_wait状态的TCP连接,说明是程序在收到对端的FIN报文后没有关闭相关的socket(有可能是fork这类函数造成的),这需要检查结束连接处理部分的代码。
  6. 如果系统中出现大量的time_wait状态的TCP连接,这种连接是正常的。出现这种连接都是由于主动关闭socket造成的,解决方案就是改成客户端主动结束连接、或者降低time_wait的时间。

Linux 网络编程——TCP的更多相关文章

  1. Linux网络编程——tcp并发服务器(poll实现)

    想详细彻底地了解poll或看懂下面的代码请参考<Linux网络编程——I/O复用之poll函数> 代码: #include <string.h> #include <st ...

  2. Linux网络编程-tcp缓存设置

    最近发现服务的逻辑完成时间很短,但是上游接收到的时间比较长,所以就怀疑是底层数据的序列化/反序列化.读写.传输有问题,然后怀疑是TCP的读写缓存是不是设置太小.现在就记录下TCP缓存的各配置项以及缓存 ...

  3. linux网络编程tcp

    之前学习的时候笔记没有保存好,这次重新编写一个案例. 客户端实现程序代码: #include <string.h> #include <stdlib.h> #include & ...

  4. Linux网络编程学习路线

    转载自:https://blog.csdn.net/lianghe_work/article 一.网络应用层编程   1.Linux网络编程01——网络协议入门 2.Linux网络编程02——无连接和 ...

  5. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

  6. TCP/UDP Linux网络编程详解

    本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信. 内容目录 1. 目标2.Linux网络编程基础2.1 嵌套字2.2 端口2.3 网络地址2.3.1 ...

  7. 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"

    [深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...

  8. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

  9. Linux 网络编程(IO模型)

    针对linux 操作系统的5类IO模型,阻塞式.非阻塞式.多路复用.信号驱动和异步IO进行整理,参考<linux网络编程>及相关网络资料. 阻塞模式 在socket编程(如下图)中调用如下 ...

随机推荐

  1. ehcache、memcache、redis三大缓存比较(转)

    最近项目组有用到这三个缓存,去各自的官方看了下,觉得还真的各有千秋!今天特意归纳下各个缓存的优缺点,仅供参考!  Ehcache 在Java项目广泛的使用.它是一个开源的.设计于提高在数据从RDBMS ...

  2. 洛谷——P1089 津津的储蓄计划

    https://www.luogu.org/problem/show?pid=1089 https://www.luogu.org/problem/show?pid=1089 题目描述 津津的零花钱一 ...

  3. Scala入门到精通——第十九节 隐式转换与隐式參数(二)

    作者:摇摆少年梦 配套视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 隐式參数中的隐式转换 函数中隐式參数使用概要 隐式转换问题梳理 1. 隐式參数中的 ...

  4. VMware Ubuntu安装具体过程

    不是每个程序猿都必须玩过linux,仅仅是博主认为如今的非常多server都是linux系统的,而自己属于那种前端也搞.后台也搞,对框架搭建也感兴趣,可是非常多生产上的框架和工具都是安装在server ...

  5. vim 保存文件的回车换行模式

    设置模式:unix,dos :set fileformat=unix  fileforman可以直接缩写为ff

  6. 防止 Chrome 屏蔽 非官方 扩展程序 教程(一)

    说明 Google Chrome,又称 Google 浏览器,是一个由 Google(谷歌)公司开发的网页浏览器.该浏览器是基于其它开源软件所撰写.包含 WebKit,目标是提升稳定性.速度和安全性. ...

  7. POJ 题目2823 Sliding Window(RMQ,固定区间长度)

    Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 46507   Accepted: 13442 ...

  8. 9.12 Binder系统_Java实现_内部机制_Client端

    Java实现中client端的RPC层(java实现)如何通过JNI来调用IPC层(C++实现)发送数据 TestServer通过addService向Service_manager注册的时候Test ...

  9. 重写ajax方法实现异步请求session过期时跳转登录页面(转)

    一般我们会在过滤器里判断登录状态,如果没登录就跳转登录页面,过滤器java核心代码如下: UserItem loginUser = (UserItem)request.getSession().get ...

  10. ArcSDE中空间数据的备份与恢复

    在采用文件形式空间数据的时代,空间数据的备份仅仅是操作系统中的文件拷贝.备份和归档的过程:而空间数据的恢复也不过是复制.覆盖的操作:在基于ArcSDE和关系型数据库的空间数据库时代,空间数据的备份更多 ...