最近刚开始啃Unix网络编程(卷1:套接字联网API),为加深TCP连接的建立和终止的理解与记忆,记下本文,方便以后翻看。

  同时留下的还有简单的Socket(TCP)类:

  mySocket.h

 #pragma once

 #include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h> #include <iostream>
#include <string> using namespace std; const int MAXLISTEN = ;
const int MAXLINE = ; class mySocket
{
public:
mySocket();
~mySocket(); bool Init();
bool Bind(const long port);
bool Listen();
bool Accept(mySocket client);
bool Connect(const string host,const long port); bool Send(mySocket client,string msg);
int Receive(mySocket client,string& msg); //设置阻塞或非阻塞
bool setNonBlock(bool flag); struct sockaddr_in getAddr();
int getFD(); private:
int m_fd;
int m_rtn;
struct sockaddr_in m_addr;
};

  mySocket.cpp

 #include <iostream>

 #include "mySocket.h"

 mySocket::mySocket()
{
m_fd = -;
} mySocket::~mySocket()
{
if(m_fd >= )
{
close(m_fd);
m_fd = -;
}
} bool mySocket::Init()
{
m_fd = socket(AF_INET,SOCK_STREAM,);
if(m_fd < )
{
cout<<"init socket error:"<<endl;
return false;
}
return true;
} bool mySocket::Bind(const long port)
{
bzero(m_addr,sizeof(m_addr));
m_addr.sin_family = AF_INET;
m_addr.sin_port = htons(port);
m_addr.sin_addr.s_addr = htonl(INADDR_ANY); if((m_rtn = bind(m_fd,(struct sockaddr*)&m_addr,sizeof(m_addr))) < )
{
cout<<"bind error"<<endl;
return false;
}
else
return true;
} bool mySocket::Listen()
{
if(listen(m_fd,MAXLISTEN) < )
{
cout<<"listen error"<<endl;
return false;
}
else
return true;
} bool mySocket::Accept(mySocket client)
{
int cliLen = sizeof(client.getAddr());
again:
if((m_rtn = accept(m_fd,(struct sockaddr*)&(client.getAddr()),&cliLen)) < )
{
if(errno == ECONNABORTED || errno == EINTR)
goto again;
else
{
cout<<"accept error"<<endl;
return false;
}
}
else
return true;
} bool mySocket::Connect(const string host,const long port)
{
m_addr.sin_family = AF_INET;
m_addr.sin_port = htons(port);
m_addr.sin_addr.s_addr = inet_addr(host.c_str()); if(connect(m_fd,(struct sockaddr *)&m_addr,sizeof(m_addr)) < )
{
cout<<"connect error"<<endl;
return false;
}
else
return true;
} bool mySocket::Send(mySocket client,string msg)
{
m_rtn = send(client.m_fd,msg.c_str(),msg.size());
if(rtn < )
{
cout<<"send error"<<endl;
return false;
}
return true;
} int mySocket::Receive(mySocket client,string& msg)
{
char buf[MAXLINE] = {};
msg.clear(); tn = recv(client.m_fd,buf,sizeof(buf));
if(rtn < )
{
cout<<"receive error"<<endl;
return -;
}
else if(rtn == )
return ;
else
{
msg = buf;
return rtn;
}
} void mySocket::setNonBlock(bool flag)
{
int opt = fcntl(m_fd,F_GETFL);
if(opt < )
{
cout<<"SetNonBlock error"<<endl;
return;
} if(flag)
opt = (opt | O_NONBLOCK);
else
opt = (opt & O_NONBLOCK); fcntl(m_fd,F_SETFL,opt);
} struct sockaddr_in mySocket::getAddr()
{
return m_addr;
} int mySocket::getFD()
{
return m_fd;
}

  1、TCP连接的建立

  TCP通过三次握手建立连接。在建立连接之前,服务器必须准备好接受外来的连接,通常通过socket、bind、listen这3个函数来完成,此过程被称为被动打开。

  (1)客户端(外来连接)通过调用connect发起主动打开。此时客户端发送一个SYN(同步)分节,通知服务器客户端将在连接中发送的数据的初始序列号。通常SYN分节不携带数据,其所在的IP数据报只包含一个IP首部、一个TCP首部及可能有的TCP选项。

  (2)服务器必须确认(ACK)客户端的SYN,同时自己也得发送一个SYN分节,包含服务器将在同一连接中发送的数据的初始序列号。服务器在单个分节中发送SYN和对客户端SYN的ACK(确认)。

  (3)客户端必须确认服务器的SYN。

  具体过程如下图:

  

  2、TCP连接终止

  TCP断开连接需要通过四次挥手来完成,具体过程如下:

  (1)某个应用进程首先调用close函数,称为该端的主动关闭。该端TCP发送一个FIN分节,表示数据发送完毕。

  (2)接收到这个FIN的对端执行被动关闭。这个FIN由TCP确认。它的接收也作为一个文件结束符(eof)传递给接收端的应用进程,因为FIN的接收意味着接收端的应用进程在相应的连接上再无额外数据可接收。

  (3)一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字,导致它的TCP也发送一个FIN。

  (4)接收到这个最终的FIN的原发送端TCP确认这个FIN。

  图示如下:

  

码海拾遗:简单Socket(TCP)类实现的更多相关文章

  1. 码海拾遗:基于MySQL Connector/C++的MySQL操作(连接池)

    1.MySQL安装及简单设置 (1)安装:在OSX系统下,可以使用万能的“brew install”命令来进行安装:brew isntall mysql(默认安装最新版的MySQL) (2)启动:br ...

  2. 码海拾遗:Linux常用命令(一)

    一.Linux系统安装 系统安装可以分两类:实体机安装Linux,虚拟机(常用虚拟机软件有两种:VMware和VirtualBox)安装Linux. 安装过程网上有很多教程,这里就不赘述了. 二.常用 ...

  3. 码海拾遗:简述C++(一)

    C++是Bjarne Stroustrup博士于1982年,在C语言的基础上引入并扩充了面向对象的概念后发明的一种新的程序语言.就与C语言的渊源而言,C++可以说是C语言的超集,它兼容C的一切(可能是 ...

  4. 码海拾遗:strcpy()、strncpy()和strcpy_s()区别

    1.strcpy() 原型:char *strcpy(char *dst,const char *src) 功能:将以src为首地址的字符串复制到以dst为首地址的字符串,包括'\0'结束符,返回ds ...

  5. 码海拾遗:Linux多线程mutex锁

    多线程计数,每个线程累加10个数. 实现: #include <stdio.h> #include <stdlib.h> #include <string.h> # ...

  6. 码海拾遗:strstr()、strcmp()和strcpy()实现

    1.strstr()实现 原型:char * strstr(const char * str1, const char * str2) 说明:判断str2是否为str1的子串,如果是则返回str2第一 ...

  7. ActionScript简单实现Socket Tcp应用协议分析器

    转自..smark http://www.cnblogs.com/smark/archive/2012/05/15/2501507.html ActionScript简单实现Socket Tcp应用协 ...

  8. C#socket编程之实现一个简单的TCP通信

    TCP(TransmissionControl Protocol)传输控制协议. 是一种可靠的.面向连接的协议(eg:打电话).传输效率低全双工通信(发送缓存&接收缓存).面向字节流.使用TC ...

  9. 基于Tcp协议的简单Socket通信实例(JAVA)

    好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西. ...

随机推荐

  1. Using sudo inside a docker container

    https://stackoverflow.com/questions/25845538/using-sudo-inside-a-docker-container FROM ubuntu:12.04 ...

  2. CSS 定位体系概述

    三种定位体系简介 框( box )布局影响因素之一,便是定位体系.定位体系也是其最为重要的影响因素. CSS2.1 中,一个框可以根据三种定位体系布局.CSS2.1 中的定位体系帮助作者使他们的文档更 ...

  3. 【Java杂货铺】JVM#Java高墙之GC与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾回收技术所围成的"高墙",墙外的人想进去,墙外的人想出来.--<深入理解Java虚拟机> 前言 上一章看了高墙的一半,接下 ...

  4. MySQL允许某个IP网段从远程访问的方法

    grant select,insert,update,create on test.* to test@'192.168.8.%' identified by '123456';     允许增删改查 ...

  5. Mysql计算时间最近多久

    -- DATE_SUB(CURDATE(), INTERVAL 3 MONTH)计算结果为当前时间的前推三个月,time字段可为时间型字符串 select * form t_user where ti ...

  6. 30)PHP,引用对象和克隆对象的区别

    复制文件.建立快捷方式的区别,克隆就是复制,引用就是快捷方式,引用的对象实际上同一个东西,修改任何一个变量,另外一个也会跟着变化.

  7. 吴裕雄--天生自然python学习笔记:python 用pygame模块制作一个音效播放器

    用 Sound 对象制作一个音效播放器. 应用程序总览 程序在执行后默认会把 WAV 音频文件加载到清单中,单击“播放”按钮可开始 播放,同时显示 “正在播放 xxx 音效”的信息 . 播放过程中,可 ...

  8. .net core ioc

    -------------------------------------- 2. ---------------------------- -----------aop

  9. webapck imports-loader和exports-loader的使用

    webapck imports-loader和exports-loader的使用

  10. 计算 $s=1+(1+2)+(1+2+3)+\cdots+(1+2+3+\cdots+n)$

    #include<stdio.h> //编写一个程序,计算 s=1+(1+2)+(1+2+3)+...+(1+2+3+...+n) 的值,要求n从键盘输入. main() { int i, ...