码海拾遗:简单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。
图示如下:
最新文章
- Spark笔记:复杂RDD的API的理解(下)
- Java 生成 UUID
- SVM3 Soft Margin SVM
- 标准库 - fmt/format.go 解读
- MySQL之count(*)与count(id)效率比较(转)
- Flexbox盒子弹性布局
- Android调用 Webservice报org.ksoap2.serialization.SoapPrimitive(转)
- ubuntu15.04更新软件源
- 第五十五节,IO多路复用select模块加socket模块,伪多线并发
- UIImage+Scale
- UVa 103 - Stacking Boxes
- msm8974 camera driver添加新摄像头kernel hal修改
- 在Design界面直接拖放控件的时候,提示AS- This view is not constrained vertically. At runtime it will jump to the left/(0,0) unless you
- Gym 101911E	";Painting the Fence";(线段树区间更新+双端队列)
- 解析XML出错,无法创建DOMDocument对象
- xbee/xbeeRPOS1、xbee/xbeePROS2C802.15.4/Digimesh功能方法
- k短路([SDOI2010]魔法猪学院)
- centos7.6 安装与配置 MongoDB yum方式
- 一些常用的mysql语句实例-以后照写
- Java switch 枚举