C++?TCP網(wǎng)絡(luò)編程詳細(xì)講解
TCP介紹與編程流程
1、面向連接的流式協(xié)議;可靠、出錯(cuò)重傳、且每收到一個(gè)數(shù)據(jù)都要給出相應(yīng)的確認(rèn)
2、通信之前需要建立鏈接
3、服務(wù)器被動(dòng)鏈接,客戶端是主動(dòng)鏈接

TCP C/S架構(gòu)

TCP客戶端編程流程
- socket 創(chuàng)建套接字
- connect 連接服務(wù)器
- send 發(fā)送請(qǐng)求
- recv 接收應(yīng)答
- close
1. 創(chuàng)建TCP套接字
socket創(chuàng)建的套接字:沒(méi)有端口、主動(dòng)連接別人
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
注:TCP是SOCK_STREAM, UDP為SOCK_DGRAM
2. connect連接服務(wù)器
如果sockfd沒(méi)有被bind綁定,第一次調(diào)用connect系統(tǒng)自動(dòng)分配隨機(jī)端口,后續(xù)使用該端口
int connect(int socket, const struct sockaddr *address, socklen_t address_len) /* socket: 套接字 address: 連接的服務(wù)器地址結(jié)構(gòu) address_len: 地址結(jié)構(gòu)長(zhǎng)度 */
注:如果客戶端和服務(wù)器通信,必須使用connect事先建立連接
3. send發(fā)送請(qǐng)求
ssize_t send(int socket, const void *buffer, size_t length, int flags) /* socket: 客戶端套接字 buffer:發(fā)送的消息 length:消息長(zhǎng)度 flags: 0 返回值: 成功:返回發(fā)送的字節(jié)數(shù) 失?。悍祷?1 */
4. recv接收應(yīng)答(默認(rèn)帶阻塞)
ssize_t recv(int socket, void *buffer, size_t length, int flags); /* socket: 客戶端套接字 buffer: 接收的消息 length:能接收的最大長(zhǎng)度 flags:0 返回值: 成功:成功接收的字節(jié)數(shù) 失?。?1 */
5. close
#include <unistd.h> int close(int fildes);
6. 客戶端編程流程代碼
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
//創(chuàng)建tcp套接字 SOCK_STREAN
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
//connect連接服務(wù)器(知道服務(wù)器地址信息)
struct sockaddr_in ser_addr;
bzero(&ser_addr, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(8000);
ser_addr.sin_addr.s_addr = inet_addr("10.9.21.211");
connect(sockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
//客戶端發(fā)送請(qǐng)求
send(sockfd, "hello tcp", strlen("hello tcp"), 0 );
//客戶端接收服務(wù)器的應(yīng)答
unsigned char buf[1500] = "";
int len = recv(sockfd, buf, sizeof(buf), 0);
printf("服務(wù)器的應(yīng)答:%s\n", buf);
//關(guān)閉套接字
close(sockfd);
return 0;
}
TCP服務(wù)端編程流程
- socket 創(chuàng)建套接字
- bind 綁定固定的port、ip地址信息
- listen 監(jiān)聽(tīng)套接字 創(chuàng)建連接隊(duì)列
- accept
- send 發(fā)送請(qǐng)求
- recv 接收應(yīng)答
- close
1. 創(chuàng)建TCP套接字
socket創(chuàng)建的套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
注:TCP是SOCK_STREAM, UDP為SOCK_DGRAM
2. bind給服務(wù)器綁定固定的port與IP地址信息
struct sockaddr_in my_addr; bzero(&my_addr, sizeof(my_addr)): my_addr.sin_family = AF_INET; my_addr.sin_port = htons(8000); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr)):
3. listen監(jiān)聽(tīng)并創(chuàng)建隊(duì)列
listen監(jiān)聽(tīng):等待客戶端的連接到來(lái),經(jīng)過(guò)三次握手(底層自動(dòng)),將客戶端放入入連接隊(duì)列
#include <sys/socket.h> int listen(int socket, int backlog); /* 功能: 1. 將監(jiān)聽(tīng)套接字由主動(dòng)變被動(dòng) 2. 為該套接字創(chuàng)建連接隊(duì)列 參數(shù): socket:變被動(dòng)的套接字 backlog:連接隊(duì)列的大小 返回值: 成功:0 失敗:-1 */
4. accept提取客戶端的連接(阻塞)
#include <sys/socket.h> int accept(int sockfd,struct sockaddr *cliaddr, socklen_t *addrlen); /* 功能: 從已連接隊(duì)列中取出一個(gè)已經(jīng)建立的連接,如果沒(méi)有任何連接可用,則進(jìn)入睡眠等待(阻塞) 參數(shù): sockfd: socket監(jiān)聽(tīng)套接字 cliaddr: 用于存放客戶端套接字地址結(jié)構(gòu) addrlen:套接字地址結(jié)構(gòu)體長(zhǎng)度的地址 返回值: 已連接套接字 */
注:返回的是一個(gè)已連接套接字,服務(wù)器只能通過(guò)已連接套接字和客戶端進(jìn)行數(shù)據(jù)通信

5. send 發(fā)送消息到客戶端
ssize_t send(int socket, const void *buffer, size_t length, int flags) /* socket: 客戶端套接字 buffer:發(fā)送的消息 length:消息長(zhǎng)度 flags: 0 返回值: 成功:返回發(fā)送的字節(jié)數(shù) 失?。悍祷?1 */
注:如果ssize_t>0,表示發(fā)送成功(實(shí)際發(fā)送的字節(jié)數(shù))
如果ssize_t為-1,表示發(fā)送是失敗
tcp不允許send發(fā)送0長(zhǎng)度報(bào)文(服務(wù)端接收0長(zhǎng)度報(bào)文則為客戶端斷開(kāi)連接)
udp允許sendto發(fā)送0長(zhǎng)度報(bào)文
6. recv 接收客戶端的消息
ssize_t recv(int socket, void *buffer, size_t length, int flags); /* socket: 客戶端套接字 buffer: 接收的消息 length:能接收的最大長(zhǎng)度 flags:0 返回值: 成功:成功接收的字節(jié)數(shù) 失敗:-1 */
注:如果ssize_t為0,表示客戶端已經(jīng)斷開(kāi)連接
如果ssize_t>0,表示recv收到的實(shí)際字節(jié)數(shù)
如果ssize_t為-1,表示recv讀取數(shù)據(jù)出錯(cuò)
7. close關(guān)閉所有套接字
#include <unistd.h> int close(套接字);
注:close后會(huì)導(dǎo)致對(duì)方recv收到0長(zhǎng)度報(bào)文
8. TCP服務(wù)端編程流程代碼
#include <stdio.h>
#include <sys/socket.h> //socket
#include <netinet/in.h> //struct sockaddr_in
#include <string.h> //memset
#include <arpa/inet.h> //htos
#include <unistd.h> //close
int main()
{
//創(chuàng)建套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0)
{
perror("cockt");
return 0;
}
//bind綁定固定的port、ip地址信息
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(9000);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
if(ret == -1)
{
perror("bind");
return 0;
}
//監(jiān)聽(tīng)套接字 創(chuàng)捷連接隊(duì)列
ret = listen(sockfd, 10);
if(ret == -1)
{
perror("listen");
return 0;
}
//提取客戶端的連接
while(1)
{
//一次只能提取一個(gè)客戶端
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
int cfd = accept(sockfd, (struct sockaddr *)&cli_addr, &cli_len);
if(cfd < 0 ) //提取失敗
{
perrer("accept\n");
break;
}
else
{
char ip[16] = "";
unsigned short port = 0;
inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, ip, 16);
port = ntohs(cli_addr.sin_port);
//打印客戶端的信息
printf("客戶端:%s %d connected\n", ip, port);
while(1)
{
//獲取客戶端的請(qǐng)求
unsigned char buf[1500] = "";
int len = recv(cfd, buf, sizeof(buf), 0);
if(len == 0) //客戶端已經(jīng)關(guān)閉
{
//關(guān)閉與客戶端連接的套接字
close(cfd);
break;
}
//應(yīng)答客戶端
send(cfd, buf, len, 0);
}
}
}
//關(guān)閉監(jiān)聽(tīng)套接字
close(sockfd);
return 0;
}
到此這篇關(guān)于C++ TCP網(wǎng)絡(luò)編程詳細(xì)講解的文章就介紹到這了,更多相關(guān)C++ TCP內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++?Socket實(shí)現(xiàn)TCP與UDP網(wǎng)絡(luò)編程
- 詳談C++ socket網(wǎng)絡(luò)編程實(shí)例(2)
- 詳談C++ socket網(wǎng)絡(luò)編程實(shí)例
- c++網(wǎng)絡(luò)編程下Linux的epoll技術(shù)和Windows下的IOCP模型
- C++基于socket UDP網(wǎng)絡(luò)編程實(shí)現(xiàn)簡(jiǎn)單聊天室功能
- C++中Socket網(wǎng)絡(luò)編程實(shí)例詳解
- C++ 網(wǎng)絡(luò)編程 總結(jié)
- C++網(wǎng)絡(luò)編程詳細(xì)講解
相關(guān)文章
C++實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器小功能
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器小功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲
這篇文章主要為大家詳細(xì)介紹了基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
使用?Visual?Studio?2022?開(kāi)發(fā)?Linux?C++?應(yīng)用程序的過(guò)程詳解
Visual?Studio?2022?引入了用于?Linux?C++?開(kāi)發(fā)的本機(jī)?WSL2?工具集,可以構(gòu)建和調(diào)試?Linux?C++?代碼,并提供了非常好的?Linux?文件系統(tǒng)性能、GUI?支持和完整的系統(tǒng)調(diào)用兼容性,這篇文章主要介紹了使用Visual?Studio?2022?開(kāi)發(fā)?Linux?C++?應(yīng)用程序,需要的朋友可以參考下2021-11-11
c++實(shí)現(xiàn)圖像像素計(jì)算的示例詳解
我們知道每張圖像都能夠用矩陣來(lái)表示,矩陣中每個(gè)元素的值表示了圖像中每個(gè)像素值,像素值的大小就對(duì)應(yīng)著圖像的亮暗,本文主要來(lái)和大家介紹一下C++進(jìn)行圖像像素計(jì)算的相關(guān)知識(shí),感興趣的可以了解下2023-12-12
C++11 lambda表達(dá)式在回調(diào)函數(shù)中的使用方式
這篇文章主要介紹了C++11 lambda表達(dá)式在回調(diào)函數(shù)中的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
C語(yǔ)言 完整游戲項(xiàng)目推箱子詳細(xì)代碼
經(jīng)典的推箱子是一個(gè)的古老游戲,目的是在訓(xùn)練你的邏輯思考能力。在一個(gè)狹小的倉(cāng)庫(kù)中,要求把木箱放到指定的位置,稍不小心就會(huì)出現(xiàn)箱子無(wú)法移動(dòng)或者通道被堵住的情況,所以需要巧妙的利用有限的空間和通道,合理安排移動(dòng)的次序和位置,才能順利的完成任務(wù)2021-11-11

