码海拾遗:简单Socket(TCP)类实现
最近刚开始啃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)类实现的更多相关文章
- 码海拾遗:基于MySQL Connector/C++的MySQL操作(连接池)
1.MySQL安装及简单设置 (1)安装:在OSX系统下,可以使用万能的“brew install”命令来进行安装:brew isntall mysql(默认安装最新版的MySQL) (2)启动:br ...
- 码海拾遗:Linux常用命令(一)
一.Linux系统安装 系统安装可以分两类:实体机安装Linux,虚拟机(常用虚拟机软件有两种:VMware和VirtualBox)安装Linux. 安装过程网上有很多教程,这里就不赘述了. 二.常用 ...
- 码海拾遗:简述C++(一)
C++是Bjarne Stroustrup博士于1982年,在C语言的基础上引入并扩充了面向对象的概念后发明的一种新的程序语言.就与C语言的渊源而言,C++可以说是C语言的超集,它兼容C的一切(可能是 ...
- 码海拾遗:strcpy()、strncpy()和strcpy_s()区别
1.strcpy() 原型:char *strcpy(char *dst,const char *src) 功能:将以src为首地址的字符串复制到以dst为首地址的字符串,包括'\0'结束符,返回ds ...
- 码海拾遗:Linux多线程mutex锁
多线程计数,每个线程累加10个数. 实现: #include <stdio.h> #include <stdlib.h> #include <string.h> # ...
- 码海拾遗:strstr()、strcmp()和strcpy()实现
1.strstr()实现 原型:char * strstr(const char * str1, const char * str2) 说明:判断str2是否为str1的子串,如果是则返回str2第一 ...
- ActionScript简单实现Socket Tcp应用协议分析器
转自..smark http://www.cnblogs.com/smark/archive/2012/05/15/2501507.html ActionScript简单实现Socket Tcp应用协 ...
- C#socket编程之实现一个简单的TCP通信
TCP(TransmissionControl Protocol)传输控制协议. 是一种可靠的.面向连接的协议(eg:打电话).传输效率低全双工通信(发送缓存&接收缓存).面向字节流.使用TC ...
- 基于Tcp协议的简单Socket通信实例(JAVA)
好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西. ...
随机推荐
- ant design vue 时间选择器只能到最大日期
<a-date-picker :disabledDate="disabledEndDate" style="width: 100%" placehold ...
- ubuntu18安装pytorch1.3
环境: ubuntu18 anaconda 创建一个新的环境 conda create -n env_name python=version 激活并进入环境中 conda activate env_n ...
- 关于nginx配置的一个报错connect() to unix:/tmp/php-cgi.sock failed (2: No such file or directory)
针对配置php的情况: linux服务器一般提示这个 connect() to unix:/tmp/php-cgi.sock failed (2: No such file or directory) ...
- 描述符(\_\_get\_\_和\_\_set\_\_和\_\_delete\_\_)
描述符(__get__和__set__和__delete__) 一.描述符 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),set(),delete()中的一个, ...
- JS - ES5与ES6面向对象编程
1.面向对象 1.1 两大编程思想 1.2 面向过程编程 POP(Process-oriented programming) 1.3 面向对象编程 OOP (Object Oriented Progr ...
- 解决UITextView滚动后无法显示完整内容
滚动UITextView,偶尔内容只显示一半,现象如下
- python学习——list
list 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推.Python有6个序列的内置类型,但最常见的是列表和元组 ...
- Unittest - Python 使用总结
Unittest - Python 使用总结 批量执行 一.UnitTest TestSuite 控制用例执行的顺序 UnitTest 框架默认 main() 方法根据 ASCII 码的顺序加载测试用 ...
- MySQL不能通过127.0.0.1访问
检查权限都是正确的,最后想到是防火墙的问题 -A INPUT -d 127.0.0.1/32 -j ACCEPT-A INPUT -s 127.0.0.1/32 -j ACCEPT 搞定
- 新年在家学java之基础篇--类&方法
面向对象 面向对象OOP,面向过程POP 面向对象三大特征 封装 继承 多态 类 类由属性(对应类中的成员变量)和行为(成员方法)来构成 类的成员变量可以先声明,不用初始化,有默认值 方法名称如果多个 ...