#include <iostream>
#include <stdio.h>
#include <windows.h> //一定要包含該頭檔案
#pragma comment(lib, "WS2_32.lib") //windwows下的socket程式設計函數庫
using namespace std;
int main()
{
WSADATA wsaData;
WORD sockVersion = MAKEWORD(, );
//windows網絡程式設計庫的版本号資訊
SOCKET sock = ; //TCP通信的socket資料結構
if (WSAStartup(sockVersion, &wsaData) != )
//WSAStartup函數是在程式中初始化并加載Windows網絡
{
cout << "initlization failed!" << endl;
exit();
//如果WSAStartup傳回值為1的話就表示ws2_32.dll檔案有問題,程式退出
}
sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//在本機上建立一個socket
if (sock == INVALID_SOCKET) //判斷socket是否建立成功
{
cout << "failed socket!" << endl;
return ; //如果建立失敗就在程式中傳回0結束程式
}
sockaddr_in sin;
//建立一個socket程式設計類型的網絡位址資料結構以便connect函數對本機建立的socket資料
//結構進行初始化。
sin.sin_family = AF_INET; //設定網絡協定族類型
sin.sin_port = htons(); //設定遠端計算機的端口号
sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//設定遠端計算機的IP位址
if (connect(sock, (sockaddr*)&sin, sizeof(sockaddr)) == -)
//初始化socket并連接配接遠端計算機
{
cout << "connect failed!" << endl;
return ; //連接配接失敗就傳回0到程式
}
char buffer[] = "\0"; //聲明一個從網絡接收資料的緩存區
int nRecv = ; //聲明一個從網絡接收到的資料位元組長度
nRecv = recv(sock, buffer, , );
//recv是一個接收網絡的TCP資料包函數,nRecv是從網絡接收到數
//據的位元組長度
if (nRecv > )
{
buffer[nRecv] = '\0';
//如果接收到網絡資料包長度大于0的話就在接收到的資料包未尾添加一個字元串
//結束符
cout << "reveive data: " << buffer << endl;
//按字元串格式輸出接收到的資料
}
closesocket(sock); //關閉這個TCP網絡通信連接配接
WSACleanup(); //釋放ws2_32.dll動态庫
}
//服務端:
#include <iostream>
#include <stdio.h>
#include <windows.h> //一定要包含該頭檔案
using namespace std;
#pragma comment(lib, "WS2_32.lib")
//windwows下的socket程式設計函數庫
int main()
{
WSADATA wsaData;
WORD sockVersion = MAKEWORD(, );
//windows網絡程式設計庫的版本号資訊
SOCKET sListen = ; //TCP通信的socket資料結構
sockaddr_in sin = {};
//建立一個socket程式設計類型的網絡位址資料結構這個用于本地
sockaddr_in remoteAddr = {};
//建立一個socket程式設計類型的網絡位址資料結構這個用于儲存遠端主機的
//IP位址和端口号
char szText[] = "TCP Server Demo";
int nAddrLen = ;
nAddrLen = sizeof(sockaddr_in);
//計算這個sockaddr_in資料結構的大小
sin.sin_port = htons();
//設定本地(這裡指服務端)計算機要打開的端口
sin.sin_family = AF_INET; //設定網絡通信的網絡協定族類型
sin.sin_addr.S_un.S_addr = INADDR_ANY;
//設定本地計算機的IP位址,一般INADDR_ANY在程式運作時
//會自動計算成本地的IP位址的
//init wsa
if (WSAStartup(sockVersion, &wsaData) != )
//WSAStartup函數是在程式中初始化并加載Windows網絡
{
cout << "initlization failed!" << endl;
exit();
//如果WSAStartup傳回值為1的話就表示ws2_32.dll檔案有問題,程式退出
}
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//在本機上建立一個socket
//使用bind函數綁定本機的ip和打開端口到本機建立的socket結構上,并初始化該socket
//重點說明一個在伺服器上是用bind函數來初始化socket,在客戶機上是用connect函數來初始化socket的喔
if (bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
cout << "bind failed!" << endl;
return ; //如果socket綁定失敗傳回程式0并退出程式
}
if (listen(sListen, ) == SOCKET_ERROR)
//listen是用來打開本地計算機的端口,參數2表示用戶端同
//時連接配接伺服器的數量,這裡是說可以同時有2個用戶端連接配接
//到本機打開的端口
{
cout << "listen failed!" << endl;
return ;
//如果打開本地端口失敗就傳回0并退出程式
}
SOCKET sClient = INADDR_ANY;
//再伺服器上再建立一個socket結構,用來儲存與一個用戶端進行通信連
//接的連接配接執行個體
while (true)
{
//accept函數是用來建立一個TCP通信連接配接執行個體的,他使用一個遠端計算機的IP位址和本地計算機上建立的一個
//socket,這兩個資訊來建立一個本地計算機到遠端計算機的一個TCP通信連接配接執行個體的socket,sClient就是目前
//程式中的這個連接配接執行個體的socket 了。注accept函數也可以直接了解為接受一個客戶機的連接配接請求。
sClient = accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen);
if (sClient == INVALID_SOCKET)
{
cout << "accept failed!" << endl;
continue;
//如果本地計算機(伺服器)接受一個用戶端連接配接請求失敗就退出監聽狀态
}
//send函數是在TCP連接配接建立之後,就來發送資料的。其中sClient是存放有一個連接配接執行個體的socket結構來
//的。這個伺服器上的send函數的socket參數和客戶機上的socket參數是不同的喔,記住這裡的socket參數是通過
//accept函數建立的喔。不是用connet函數和bind函數建立喔。一定要記住這個sClient是一個關鍵來的。然後
//szText就是我們想要發送的資料了。這裡我們向連接配接到該伺服器的用戶端發送了一個“TCP Server Demo”的資訊。
send(sClient, szText, strlen(szText), );
closesocket(sClient);
//關閉這個用accept函數建立socket對象,關閉與remoteAddr連接配接通信。
//remoteAddr這結構理包含了有遠端計算機的IP和端口号資訊,當客戶機
//使用connect函數發送一個連接配接請求時,被accept函數接受并處理後,遠
//程計算機的IP位址和端口資訊就被填到了remoteAddr這個結構中去
}
closesocket(sListen);
//關閉本地計算機(伺服器)上的由bind函數建立的socket對象,關閉本機
//打開的端口,關閉伺服器
WSACleanup();
//釋放ws2_32.dll動态庫
}