在另外一邊的客戶端,我們分析一下TCPClientSock的建立過程。
class TCPClientSock: public BaseSock{
private:
sockaddr_in serverSockAddr;
protected:
char* preBuffer;
int preBufferSize;
mutable int preReceivedLength;
public:
TCPClientSock(
const char* server_IP,
unsigned short server_port,
int pre_buffer_size = 32);
virtual ~TCPClientSock();
int TCPReceive() const;
int TCPSend(const char* send_data,
const int& data_length) const;
};
我們看到TCPClientSock的類與TCPServerSock很類似,構(gòu)造函數(shù)的差別是,TCPClientSock需要提供server端的IP地址和端口號(hào)。
TCPClientSock::TCPClientSock(
const char *server_IP,
unsigned short server_port,
int pre_buffer_size):
preBufferSize(pre_buffer_size),
preReceivedLength(0)
{
preBuffer = new char[preBufferSize];
sockFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockFD < 0) {
sockClass::error_info("sock() failed.");
}
memset(&serverSockAddr, 0, sizeof(serverSockAddr));
serverSockAddr.sin_family = AF_INET;
serverSockAddr.sin_addr.s_addr = inet_addr(server_IP);
serverSockAddr.sin_port = htons(server_port);
if (connect(sockFD,
(struct sockaddr*)&serverSockAddr,
sizeof(serverSockAddr)) < 0 ) {
sockClass::error_info("connect() failed.");
}
}
TCPClientSock::~TCPClientSock()
{
delete [] preBuffer;
close(sockFD);
}
TCPClientSock通過socket()建立起sockFD,然后指定服務(wù)器的serverSockAddr,然后通過connect()向serverSockAddr指定的服務(wù)器發(fā)出握手請(qǐng)求。需要說明的是,調(diào)用connect()的時(shí)候,系統(tǒng)會(huì)檢查TCPClientSock的sockFD是否已經(jīng)綁定了本機(jī)的SockAddr,事實(shí)上我們也可以通過bind()將本機(jī)的IP和指定的端口號(hào)綁定在這個(gè)sockFD上,但是我們并不關(guān)心這個(gè)IP地址和端口號(hào)(況且很多主機(jī)并沒有公網(wǎng)IP,特別在中國(guó)),所以通常我們不自己去綁定,這樣系統(tǒng)就會(huì)幫我們完成綁定工作,分配一個(gè)空閑的端口號(hào)作為本機(jī)地址的端口號(hào)。
這樣TCPClientSock具有來向(本機(jī)地址,通常由系統(tǒng)自動(dòng)完成綁定,也可以指定)和去向(指定的server端地址)的地址信息,所以可以收發(fā)信息。于是,TCPClientSock發(fā)出的第一個(gè)數(shù)據(jù)報(bào)是發(fā)給server監(jiān)聽socket的握手請(qǐng)求數(shù)據(jù)報(bào),TCPListenSock接收這個(gè)數(shù)據(jù)報(bào)后,將相關(guān)信息傳遞給TCPServerSock建立新的sockFD,我們上一節(jié)講到,這個(gè)新的sockFD建立起來之后馬上就向client端返回一個(gè)數(shù)據(jù)報(bào):一方面表示接受第一次握手請(qǐng)求,另外一方面發(fā)出第二次握手請(qǐng)求。
收到第二次握手請(qǐng)求后,connect()才會(huì)返回,不然就會(huì)阻塞,非常“盡力”的去連接server。這個(gè)“盡力”的程度跟系統(tǒng)有關(guān),在我的試驗(yàn)中,windows下很快,就幾秒;而Debian則接近6分鐘!
connect()返回的同時(shí),向server發(fā)出了第三次握手的信息,這個(gè)信息是對(duì)第二次握手請(qǐng)求的認(rèn)可。所以,第一次和第二次握手包含著連接的請(qǐng)求;而第二次和第三次握手則包含著對(duì)握手請(qǐng)求的認(rèn)可,他們都是在告訴對(duì)方:我知道并同意你連接上我了。
至此,TCP三次握手的概念在socket中完整的實(shí)現(xiàn),建立起數(shù)據(jù)流的TCP通信通道。
posted on 2010-06-07 00:46
lf426 閱讀(1850)
評(píng)論(1) 編輯 收藏 引用 所屬分類:
SDL入門教程 、
Linux與C++ 、
socket 編程入門教程