Socket介紹:
socket即套接字,端口號(hào)拼接到IP地址就構(gòu)成了套接字基公。如果IP地址是169.254.24幅慌,而端口號(hào)是3000欠痴,那么得到套接字就是(169.254.24:3000),即(主機(jī)IP地址:端口號(hào))。
三種不同類型的套接字:
1特占、 (SOCK-STREAM)流式套接字:提供一種可靠的懊纳、面向連接的雙向數(shù)據(jù)傳輸服務(wù)闺兢,實(shí)現(xiàn)了數(shù)據(jù)無(wú)差錯(cuò)、無(wú)重復(fù)的發(fā)送。發(fā)送大批量的數(shù)據(jù)或者對(duì)數(shù)據(jù)傳輸有較高的要求時(shí),可以使用流式套接字泄鹏。
2车猬、 (SOCK-DGRAM)數(shù)據(jù)報(bào)套接字: 提供一種無(wú)連接伏嗜、不可靠的雙向數(shù)據(jù)傳輸服務(wù)。數(shù)據(jù)包以獨(dú)立的形式被發(fā)送轩猩,數(shù)據(jù)在傳輸過(guò)程中可能會(huì)丟失或重復(fù),并且不能保證在接收端按發(fā)送順序接收數(shù)據(jù)热鞍。出現(xiàn)差錯(cuò)的可能性較小或允許部分傳輸出錯(cuò)的應(yīng)用場(chǎng)合澄港,可以使用數(shù)據(jù)報(bào)套接字狱意。
3藏姐、(SOCK-RAW)原始套接字:該套接字允許對(duì)較低層協(xié)議(如IP或ICMP)進(jìn)行直接訪問(wèn),常用于網(wǎng)絡(luò)協(xié)議分析护姆,檢驗(yàn)新的網(wǎng)絡(luò)協(xié)議實(shí)現(xiàn),也可用于測(cè)試新配置或安裝的網(wǎng)絡(luò)設(shè)備添祸。
客戶端/服務(wù)端模式:
網(wǎng)絡(luò)架構(gòu)使用客戶端(Client)-服務(wù)器(Server)模式(簡(jiǎn)稱C/S)亚侠,即客戶端向服務(wù)器發(fā)出請(qǐng)求滞谢,服務(wù)器接收請(qǐng)求后禾酱,提供相應(yīng)的服務(wù)垦江。
服務(wù)端:建立socket,聲明自身的端口號(hào)和地址并綁定到socket,使用listen打開(kāi)監(jiān)聽(tīng)瓢剿,然后不斷用accept去查看是否有連接,如果有悠轩,捕獲socket火架,并通過(guò)recv獲取消息的內(nèi)容音比,通信完成后調(diào)用closeSocket關(guān)閉這個(gè)對(duì)應(yīng)accept到的socket骚亿,如果不再需要等待任何客戶端連接泥技,那么用closeSocket關(guān)閉掉自身的socket。
客戶端:建立socket兼贸,通過(guò)端口號(hào)和地址確定目標(biāo)服務(wù)器段直,使用Connect連接到服務(wù)器,send發(fā)送消息溶诞,等待處理鸯檬,通信完成后調(diào)用closeSocket關(guān)閉socket。
TCP編程步驟:
一螺垢、服務(wù)端
1喧务、加載套接字庫(kù),創(chuàng)建套接字(WSAStartup()/socket());
2枉圃、綁定套接字到一個(gè)IP地址和一個(gè)端口上(bind());
3功茴、將套接字設(shè)置為監(jiān)聽(tīng)模式等待連接請(qǐng)求(listen());
4孽亲、請(qǐng)求到來(lái)后坎穿,接受連接請(qǐng)求,返回一個(gè)新的對(duì)應(yīng)于此次連接的套接字(accept())返劲;
5玲昧、用返回的套接字和客戶端進(jìn)行通信(send()/recv());
6篮绿、返回孵延,等待另一個(gè)連接請(qǐng)求;
7亲配、關(guān)閉套接字尘应,關(guān)閉加載的套接字庫(kù)(closesocket()/WSACleanup())惶凝;
二、客戶端
1犬钢、加載套接字庫(kù)梨睁,創(chuàng)建套接字(WSAStartup()/socket());
2娜饵、向服務(wù)器發(fā)出連接請(qǐng)求(connect())坡贺;
3、和服務(wù)器進(jìn)行通信(send()/recv())箱舞;
4遍坟、關(guān)閉套接字,關(guān)閉加載的套接字庫(kù)(closesocket()/WSACleanup())晴股;
TCP服務(wù)端代碼
#include "pch.h"
#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main(int argc, char* argv[])
{
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
//創(chuàng)建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET)
{
cout << "create socket error !" << endl;
return 0;
}
//綁定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
cout << "bind error !" << endl;
}
//開(kāi)始監(jiān)聽(tīng)
if (listen(slisten, 5) == SOCKET_ERROR)
{
cout << "listen error !" << endl;
return 0;
}
//循環(huán)接收數(shù)據(jù)
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
while (true)
{
cout << "阻塞愿伴。。。。等待連接刷后。碟联。湾宙。" << endl;
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET)
{
cout << "accept error !" << endl;
continue;
}
cout << "接受到一個(gè)連接:" << inet_ntoa(remoteAddr.sin_addr) << endl;
//接收數(shù)據(jù)
int ret = recv(sClient, revData, 255, 0);
if (ret > 0)
{
revData[ret] = 0x00;
printf(revData);
}
//發(fā)送數(shù)據(jù)
const char * sendData = "你好,TCP客戶端!\n";
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
return 0;
}
TCP客戶端代碼
#include "stdafx.h"
#include<winsock2.h>
#include<iostream>
#include<string>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main()
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(sockVersion, &data) != 0)
{
return 0;
}
while (true)
{
SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sclient == INVALID_SOCKET)
{
cout << "invalid socket!" << endl;
return 0;
}
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
//連接失敗
cout << "connect error !" << endl;
closesocket(sclient);
return 0;
}
string data;
cin >> data;
const char * sendData;
sendData = data.c_str(); //string轉(zhuǎn)const char*
/*
send()用來(lái)將數(shù)據(jù)由指定的socket傳給對(duì)方主機(jī)
int send(int s, const void * msg, int len, unsigned int flags)
s為已建立好連接的socket,msg指向數(shù)據(jù)內(nèi)容幻妓,len則為數(shù)據(jù)長(zhǎng)度,參數(shù)flags一般設(shè)0
成功則返回實(shí)際傳送出去的字符數(shù)劫拢,失敗返回-1肉津,錯(cuò)誤原因存于error
*/
send(sclient, sendData, strlen(sendData), 0);
char recData[255];
int ret = recv(sclient, recData, 255, 0);
if (ret>0)
{
recData[ret] = 0x00;
cout << recData << endl;
}
closesocket(sclient);
}
WSACleanup();
system("pause");
return 0;
}