码海拾遗:简单Socket(TCP)类实现
Posted 落雷
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了码海拾遗:简单Socket(TCP)类实现相关的知识,希望对你有一定的参考价值。
最近刚开始啃Unix网络编程(卷1:套接字联网API),为加深TCP连接的建立和终止的理解与记忆,记下本文,方便以后翻看。
同时留下的还有简单的Socket(TCP)类:
mySocket.h
1 #pragma once 2 3 #include <unistd.h> 4 #include <sys/socket.h> 5 #include <arpa/inet.h> 6 #include <strings.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 10 #include <iostream> 11 #include <string> 12 13 using namespace std; 14 15 const int MAXLISTEN = 20; 16 const int MAXLINE = 1024; 17 18 class mySocket 19 { 20 public: 21 mySocket(); 22 ~mySocket(); 23 24 bool Init(); 25 bool Bind(const long port); 26 bool Listen(); 27 bool Accept(mySocket client); 28 bool Connect(const string host,const long port); 29 30 bool Send(mySocket client,string msg); 31 int Receive(mySocket client,string& msg); 32 33 //设置阻塞或非阻塞 34 bool setNonBlock(bool flag); 35 36 struct sockaddr_in getAddr(); 37 int getFD(); 38 39 private: 40 int m_fd; 41 int m_rtn; 42 struct sockaddr_in m_addr; 43 };
mySocket.cpp
1 #include <iostream> 2 3 #include "mySocket.h" 4 5 mySocket::mySocket() 6 { 7 m_fd = -1; 8 } 9 10 mySocket::~mySocket() 11 { 12 if(m_fd >= 0) 13 { 14 close(m_fd); 15 m_fd = -1; 16 } 17 } 18 19 bool mySocket::Init() 20 { 21 m_fd = socket(AF_INET,SOCK_STREAM,0); 22 if(m_fd < 0) 23 { 24 cout<<"init socket error:"<<endl; 25 return false; 26 } 27 return true; 28 } 29 30 bool mySocket::Bind(const long port) 31 { 32 bzero(m_addr,sizeof(m_addr)); 33 m_addr.sin_family = AF_INET; 34 m_addr.sin_port = htons(port); 35 m_addr.sin_addr.s_addr = htonl(INADDR_ANY); 36 37 if((m_rtn = bind(m_fd,(struct sockaddr*)&m_addr,sizeof(m_addr))) < 0) 38 { 39 cout<<"bind error"<<endl; 40 return false; 41 } 42 else 43 return true; 44 } 45 46 bool mySocket::Listen() 47 { 48 if(listen(m_fd,MAXLISTEN) < 0) 49 { 50 cout<<"listen error"<<endl; 51 return false; 52 } 53 else 54 return true; 55 } 56 57 bool mySocket::Accept(mySocket client) 58 { 59 int cliLen = sizeof(client.getAddr()); 60 again: 61 if((m_rtn = accept(m_fd,(struct sockaddr*)&(client.getAddr()),&cliLen)) < 0) 62 { 63 if(errno == ECONNABORTED || errno == EINTR) 64 goto again; 65 else 66 { 67 cout<<"accept error"<<endl; 68 return false; 69 } 70 } 71 else 72 return true; 73 } 74 75 bool mySocket::Connect(const string host,const long port) 76 { 77 m_addr.sin_family = AF_INET; 78 m_addr.sin_port = htons(port); 79 m_addr.sin_addr.s_addr = inet_addr(host.c_str()); 80 81 if(connect(m_fd,(struct sockaddr *)&m_addr,sizeof(m_addr)) < 0) 82 { 83 cout<<"connect error"<<endl; 84 return false; 85 } 86 else 87 return true; 88 } 89 90 bool mySocket::Send(mySocket client,string msg) 91 { 92 m_rtn = send(client.m_fd,msg.c_str(),msg.size()); 93 if(rtn < 0) 94 { 95 cout<<"send error"<<endl; 96 return false; 97 } 98 return true; 99 } 100 101 int mySocket::Receive(mySocket client,string& msg) 102 { 103 char buf[MAXLINE] = {0}; 104 msg.clear(); 105 106 tn = recv(client.m_fd,buf,sizeof(buf)); 107 if(rtn < 0) 108 { 109 cout<<"receive error"<<endl; 110 return -1; 111 } 112 else if(rtn == 0) 113 return 0; 114 else 115 { 116 msg = buf; 117 return rtn; 118 } 119 } 120 121 void mySocket::setNonBlock(bool flag) 122 { 123 int opt = fcntl(m_fd,F_GETFL); 124 if(opt < 0) 125 { 126 cout<<"SetNonBlock error"<<endl; 127 return; 128 } 129 130 if(flag) 131 opt = (opt | O_NONBLOCK); 132 else 133 opt = (opt & O_NONBLOCK); 134 135 fcntl(m_fd,F_SETFL,opt); 136 } 137 138 struct sockaddr_in mySocket::getAddr() 139 { 140 return m_addr; 141 } 142 143 int mySocket::getFD() 144 { 145 return m_fd; 146 }
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)类实现的主要内容,如果未能解决你的问题,请参考以下文章