(18條消息) C++:實現socket通信(TCP/IP)實例_Cche的博客-CSDN博客_c++ socket
一、什么是TCP/IP?
TCP提供基於IP環境下的數據可靠性傳輸,事先需要進行三次握手來確保數據傳輸的可靠性。詳細的博主不再贅述,感興趣的朋友可以去search一下。
二、什么是socket?
socket顧名思義就是套接字的意思,用於描述地址和端口,是一個通信鏈的句柄。應用程序通過socket向網絡發出請求或者回應。
socket編程有三種,流式套接字(SOCK_STREAM),數據報套接字(SOCK_DGRAM),原始套接字(SOCK_RAW),前兩者較常用。基於TCP的socket編程是流式套接字。
三、client/server即C/S模式:
TCP/IP通信中,主要是進行C/S交互。廢話不多說,下面看看具體交互內容:
服務端:建立socket,申明自身的port和IP,並綁定到socket,使用listen監聽,然后不斷用accept去查看是否有連接。如果有,捕獲socket,並通過recv獲取消息的內容,通信完成后調用closeSocket關閉這個對應accept到的socket。如果不需要等待任何客戶端連接,那么用closeSocket直接關閉自身的socket。
客戶端:建立socket,通過端口號和地址確定目標服務器,使用Connect連接到服務器,send發送消息,等待處理,通信完成后調用closeSocket關閉socket。
四、編程步驟
1、server端
(1)加載套接字庫,創建套接字(WSAStartup()/socket());
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
void initialization();
int main()
{
//創建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
}
void initialization() {
//初始化套接字庫
WORD w_req = MAKEWORD(2, 2);//版本號
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字庫失敗!" << endl;
}
else {
cout << "初始化套接字庫成功!" << endl;
}
//檢測版本號
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字庫版本號不符!" << endl;
WSACleanup();
}
else {
cout << "套接字庫版本正確!" << endl;
}
//填充服務端地址信息
}
(2)綁定套接字到一個IP地址和一個端口上(bind());
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(5010);
(3)將套接字設置為監聽模式等待連接請求(listen());
//設置套接字為監聽狀態
if (listen(s_server, SOMAXCONN) < 0)
{
cout << "設置監聽狀態失敗!" << endl;
WSACleanup();
}
else
{
cout << "設置監聽狀態成功!" << endl;
}
cout << "服務端正在監聽連接,請稍候...." << endl;
(4)請求到來后,接受連接請求,返回一個新的對應於此次連接的套接字(accept());
//接受連接請求
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
if (s_accept == SOCKET_ERROR)
{
cout << "連接失敗!" << endl;
WSACleanup();
return 0;
}
cout << "連接建立,准備接受數據" << endl;
(5)用返回的套接字和客戶端進行通信(send()/recv());
//接收數據
while (1)
{
recv_len = recv(s_accept, recv_buf, 100, 0);
if (recv_len < 0)
{
cout << "接受失敗!" << endl;
break;
}
else
{
cout << "客戶端信息:" << recv_buf << endl;
}
cout << "請輸入回復信息:";
cin >> send_buf;
send_len = send(s_accept, send_buf, 100, 0);
if (send_len < 0)
{
cout << "發送失敗!" << endl;
break;
}
}
(6)返回,等待另一個連接請求;
(7)關閉套接字,關閉加載的套接字庫(closesocket()/WSACleanup());
//關閉套接字
closesocket(s_server);
closesocket(s_accept);
//釋放DLL資源
WSACleanup();
return 0;
2、Client端
(1)加載套接字庫,創建套接字(WSAStartup()/socket);
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
void initialization();
int main()
{
//創建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
}
void initialization() {
//初始化套接字庫
WORD w_req = MAKEWORD(2, 2);//版本號
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字庫失敗!" << endl;
}
else {
cout << "初始化套接字庫成功!" << endl;
}
//檢測版本號
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字庫版本號不符!" << endl;
WSACleanup();
}
else {
cout << "套接字庫版本正確!" << endl;
}
//填充服務端地址信息
}
(2)向服務器發出連接請求(connect());
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << "服務器連接失敗!" << endl;
WSACleanup();
}
else {
cout << "服務器連接成功!" << endl;
}
(3)和服務器進行通信(send()/recv());
//發送,接收數據
while (1) {
cout << "請輸入發送信息:";
cin >> send_buf;
send_len = send(s_server, send_buf, 100, 0);
if (send_len < 0) {
cout << "發送失敗!" << endl;
break;
}
recv_len = recv(s_server, recv_buf, 100, 0);
if (recv_len < 0) {
cout << "接受失敗!" << endl;
break;
}
else {
cout << "服務端信息:" << recv_buf << endl;
}
}
(4)關閉套接字,關閉加載的套接字庫(closesocket()/WSACleanup())
//關閉套接字
closesocket(s_server);
//釋放DLL資源
WSACleanup();
五、Windows下基於VS2017實現的socket簡單實例(TCP/IP)
(1)server端代碼
#include "pch.h"
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int main() {
//定義長度變量
int send_len = 0;
int recv_len = 0;
int len = 0;
//定義發送緩沖區和接受緩沖區
char send_buf[100];
char recv_buf[100];
//定義服務端套接字,接受請求套接字
SOCKET s_server;
SOCKET s_accept;
//服務端地址客戶端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
initialization();
//填充服務端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(5010);
//創建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (bind(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << "套接字綁定失敗!" << endl;
WSACleanup();
}
else {
cout << "套接字綁定成功!" << endl;
}
//設置套接字為監聽狀態
if (listen(s_server, SOMAXCONN) < 0) {
cout << "設置監聽狀態失敗!" << endl;
WSACleanup();
}
else {
cout << "設置監聽狀態成功!" << endl;
}
cout << "服務端正在監聽連接,請稍候...." << endl;
//接受連接請求
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
if (s_accept == SOCKET_ERROR) {
cout << "連接失敗!" << endl;
WSACleanup();
return 0;
}
cout << "連接建立,准備接受數據" << endl;
//接收數據
while (1) {
recv_len = recv(s_accept, recv_buf, 100, 0);
if (recv_len < 0) {
cout << "接受失敗!" << endl;
break;
}
else {
cout << "客戶端信息:" << recv_buf << endl;
}
cout << "請輸入回復信息:";
cin >> send_buf;
send_len = send(s_accept, send_buf, 100, 0);
if (send_len < 0) {
cout << "發送失敗!" << endl;
break;
}
}
//關閉套接字
closesocket(s_server);
closesocket(s_accept);
//釋放DLL資源
WSACleanup();
return 0;
}
void initialization() {
//初始化套接字庫
WORD w_req = MAKEWORD(2, 2);//版本號
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字庫失敗!" << endl;
}
else {
cout << "初始化套接字庫成功!" << endl;
}
//檢測版本號
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字庫版本號不符!" << endl;
WSACleanup();
}
else {
cout << "套接字庫版本正確!" << endl;
}
//填充服務端地址信息
}
(2)client端:
#include "pch.h"
#include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void initialization();
int main() {
//定義長度變量
int send_len = 0;
int recv_len = 0;
//定義發送緩沖區和接受緩沖區
char send_buf[100];
char recv_buf[100];
//定義服務端套接字,接受請求套接字
SOCKET s_server;
//服務端地址客戶端地址
SOCKADDR_IN server_addr;
initialization();
//填充服務端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(1234);
//創建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << "服務器連接失敗!" << endl;
WSACleanup();
}
else {
cout << "服務器連接成功!" << endl;
}
//發送,接收數據
while (1) {
cout << "請輸入發送信息:";
cin >> send_buf;
send_len = send(s_server, send_buf, 100, 0);
if (send_len < 0) {
cout << "發送失敗!" << endl;
break;
}
recv_len = recv(s_server, recv_buf, 100, 0);
if (recv_len < 0) {
cout << "接受失敗!" << endl;
break;
}
else {
cout << "服務端信息:" << recv_buf << endl;
}
}
//關閉套接字
closesocket(s_server);
//釋放DLL資源
WSACleanup();
return 0;
}
void initialization() {
//初始化套接字庫
WORD w_req = MAKEWORD(2, 2);//版本號
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字庫失敗!" << endl;
}
else {
cout << "初始化套接字庫成功!" << endl;
}
//檢測版本號
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字庫版本號不符!" << endl;
WSACleanup();
}
else {
cout << "套接字庫版本正確!" << endl;
}
//填充服務端地址信息
}
注:對於入門級別學習的同學一些使用指導,想要讓這倆程序跑起來,如果只有一台電腦,那么只需要在一台電腦上VS中創建兩個不同的控制台應用程序,然后把server和client代碼分別copy到這倆新建項目的主程序中,直接運行即可。
六、運行結果顯示

原文鏈接:https://blog.csdn.net/qq_27923041/article/details/83857964
