码海拾遗:简单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以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西. ...
随机推荐
- SEO优化技巧
一.搜索引擎工作原理 当我们在输入框中输入关键词,点击搜索或查询时,然后得到结果.深究其背后的故事,搜索引擎做了很多事情. 在搜索引擎网站,比如百度,在其后台有一个非常庞大的数据库,里面存储了海量的关 ...
- Python笔记_第一篇_面向过程_第一部分_5.Python数据类型之集合类型(set)
集合!Python中的集合数据基本上是为了方便数学计算使用的. 什么是集合? 集合就是“确定的一堆东西”.集合里面的东西叫做元素. 特点:1. 集合里面是没有重复的元素的. 2. ...
- mac 编程环境
新mac (EI Capitan),需要在python中使用xgboost,通过pip安装未成功. 配置pip cat $HOME/Library/Application\ Support/pip/p ...
- 计算文本长度-boundingRectWithSize
- (void)viewDidLoad { [super viewDidLoad]; //新建lable控件 UILabel *lable=[[UILabel alloc]init]; labl ...
- Servlet&JSP复习笔记 01
1. Servlet 含义:服务器端的小程序,它只是服务器中的一部分. Servlet Little 标准:Sun公司制定的一种用来扩展Web服务器功能的组件规范. a. 扩展web服务器功能:扩展w ...
- EXAM-2018-08-21
EXAM-2018-08-21 自己真的是菜的恐怖 D:Fence Building 欧拉公式:V-E+F=2 在平面中:V为顶点个数,E为边数,F为区域数 在简单几何体中:V为顶点个数,E为边数,F ...
- www、数组的equals、接口和抽象类、装箱拆箱、final赋值
目录 2019.12.31 刷题笔记 2019.12.31 刷题笔记 www www是World Wide Web的缩写 数组的equals 数组是一个对象,不同类型的数组具有不同的类.数组是一种引用 ...
- AdminWebSessionManager AdminAuthorizingRealm ShiroConfig ShiroExceptionHandler
package org.linlinjava.litemall.admin.shiro; import com.alibaba.druid.util.StringUtils; import org.a ...
- D - Project Presentation(DFS序+倍增LCA)
You are given a tree that represents a hierarchy in a company, where the parent of node u is their d ...
- JavaScript中遍历数组,最好不要用for...in
先看一段代码 var arr = [2,3,4,5]; for(var i = 0; i < arr.length; i++){ console.log(i,"类型:"+ty ...