TCP服務(wù)器實現(xiàn)數(shù)據(jù)通信
前言
今天我們要介紹的是使用TCP協(xié)議實現(xiàn)數(shù)據(jù)通信,相比于之前寫的UDP服務(wù)器實現(xiàn)數(shù)據(jù)信,在主體邏輯上并沒有差別??蛻舳讼蚍?wù)器發(fā)送信息,服務(wù)器接受信息并回顯,因為UDP是面向數(shù)據(jù)報,而TCP是面向連接的,所以在實現(xiàn)的時候接口上會有一些差別,下面,我們具體來看看UDP和TCP在編碼的實現(xiàn)上有什么不同。
1.接口介紹
因為TCP是面向連接的,所以服務(wù)器創(chuàng)建完套接字,然后綁定成功后,將套接字設(shè)置為監(jiān)聽套接字
服務(wù)器啟動之后,首先需要根據(jù)監(jiān)聽套接字建立連接,建立連接成功后返回一個新的文件描述符,后續(xù)的通信都是按照這個新的文件描述符按照讀寫文件的形式進行讀寫數(shù)據(jù)。
對于客戶端來說創(chuàng)建完套接字之后,客戶端啟動之后首先需要建立連接
listen():設(shè)置sock為監(jiān)聽狀態(tài)
#include <sys/types.h> #include <sys/socket.h> int listen(int sockfd, int backlog);
sockfd:創(chuàng)建套接字的返回值
backlog:底層全連接隊列的長度
accept():服務(wù)端建立連接
#include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:監(jiān)聽套接字
struct sockaddr* addr:輸出型參數(shù),可以獲取服務(wù)端的IP地址和port端口號
socklen_t* addrlen:結(jié)構(gòu)體的大小
返回值:返回一個新打開的文件描述符
connect():客戶端建立連接
#include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockfd:創(chuàng)建套接字返回值
struct sockaddr* addr:輸出型參數(shù),用來填寫需要訪問的服務(wù)端的IP地址和port端口號
socklen_t addrlen:結(jié)構(gòu)體的大小
2.編寫服務(wù)器
tcpServer.hpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "log.hpp"
namespace server
{
using namespace std;
enum
{
USAGE_ERR = 1,
SOCKET_ERR,
BIND_ERR,
LISTEN_ERR
};
static const uint16_t gport = 8080;
static const int gback = 5;
class TcpServer
{
public:
TcpServer(const uint16_t &port = gport)
: _port(gport), _sock(-1)
{}
void InitServer()
{
_sock = socket(AF_INET, SOCK_STREAM, 0);
if (_sock < 0)
{
logMessage(FATAL, "create socket error");
exit(SOCKET_ERR);
}
logMessage(NORMAL, "create socket success");
// 綁定:
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = INADDR_ANY;
if (bind(_sock, (struct sockaddr *)&local, sizeof(local)) < 0)
{
logMessage(FATAL, "bind socket error");
exit(BIND_ERR);
}
logMessage(NORMAL, "bind socket success");
// 設(shè)置sock為監(jiān)聽狀態(tài):
if (listen(_sock, gback) < 0)
{
logMessage(FATAL, "listen socket error");
exit(LISTEN_ERR);
}
logMessage(NORMAL, "listen socket success");
}
void start()
{
for (;;)
{
// 建立連接:
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int sock = accept(_sock, (struct sockaddr *)&peer, &len);
if (sock < 0)
{
logMessage(ERROR, "accept error, next");
continue;
}
logMessage(NORMAL, "accept a new link success");
std::cout << "sock: " << sock << std::endl;
//未來通信全部用sock,面向字節(jié)流的,后續(xù)全部都是文件操作:
serviceIO(sock);
close(sock);
}
}
void serviceIO(int sock)
{
char buffer[1024];
while(true)
{
ssize_t n = read(sock,buffer,sizeof(buffer)-1);
if(n > 0)
{
buffer[n] = 0;
cout << "recvice message: " << buffer << endl;
string outbuffer = buffer;
outbuffer += "[server echo]";
write(sock,outbuffer.c_str(),outbuffer.size());
}
else if(n == 0)
{
// 代表client退出
logMessage(NORMAL, "client quit, me too!");
break;
}
}
}
~TcpServer()
{}
private:
int _sock;
uint16_t _port;
};
}tcpServer.cc:啟動服務(wù)器
#include"tcpServer.hpp"
#include<memory>
using namespace server;
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc,char* argv[])
{
if(argc != 2)
{
Usage(argv[0]);
exit(USAGE_ERR);
}
uint16_t port = atoi(argv[1]);
unique_ptr<TcpServer> tcs(new TcpServer(port));
tcs->InitServer();
tcs->start();
return 0;
}3.編寫客戶端
tcpClient.hpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
namespace client
{
using namespace std;
class TcpClient
{
public:
TcpClient(const string& serverip,const uint16_t port)
:_serverip(serverip),_port(port),_sock(-1)
{}
void InitClient()
{
_sock = socket(AF_INET,SOCK_STREAM,0);
if(_sock < 0)
{
cerr << "create sock fail" << endl;
exit(-1);
}
}
void start()
{
//建立連接:
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(_port);
server.sin_addr.s_addr = inet_addr(_serverip.c_str());
if(connect(_sock,(struct sockaddr*)&server,sizeof(server)) != 0)
{
cerr << "connect fail" << endl;
}
else
{
string message;
while(true)
{
cout << "Please Enter: ";
getline(cin,message);
write(_sock,message.c_str(),message.size());
char buffer[1024];
int n = read(_sock,buffer,sizeof(buffer)-1);
if(n > 0)
{
buffer[n] = 0;
cout << "Server回復(fù): " << buffer << endl;
}
else
{
break;
}
}
}
}
~TcpClient()
{
if(_sock >= 0)
close(_sock);
}
private:
string _serverip;
uint16_t _port;
int _sock;
};
} // namespace clienttcpClient.cc:啟動客戶端
#include"tcpClient.hpp"
#include<memory>
using namespace client;
static void Usage(string proc)
{
cout << "\nUsage:\n\t" << proc << " serverip serverport\n\n";
}
int main(int argc,char* argv[])
{
if(argc != 3)
{
Usage(argv[0]);
exit(-1);
}
uint16_t port = atoi(argv[2]);
string ip = argv[1];
unique_ptr<TcpClient> tcc(new TcpClient(ip,port));
tcc->InitClient();
tcc->start();
return 0;
}4.編譯鏈接
makefile:
.PHONY:all all:tcpServer tcpClient tcpServer:tcpServer.cc g++ -o $@ $^ -std=c++11 tcpClient:tcpClient.cc g++ -o $@ $^ -std=c++11 .PHONY:clean clean: rm tcpServer tcpClient
5.測試

如圖所示,服務(wù)端和客戶端可以完成正常的數(shù)據(jù)通信了。
6.總結(jié)
TCP協(xié)議和UDP協(xié)議在數(shù)據(jù)通信的實現(xiàn)中,除了一些接口使用的不同之外,其實并沒有太大的不同,在之前說的UDP是面向數(shù)據(jù)報的而TCP是面向字節(jié)流的,這些特性又是如何體現(xiàn)的呢?關(guān)于這個問題,博主將在后面的文章中會為大家繼續(xù)進行介紹。不要錯過哦!
到此這篇關(guān)于TCP服務(wù)器實現(xiàn)數(shù)據(jù)通信的文章就介紹到這了,更多相關(guān)TCP服務(wù)器數(shù)據(jù)通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++實現(xiàn)TCP客戶端及服務(wù)器Recv數(shù)據(jù)篩選處理詳解
- TCP服務(wù)器實現(xiàn)數(shù)據(jù)通信
- Python基于socket實現(xiàn)TCP/IP客戶和服務(wù)器通信
- C++多線程實現(xiàn)TCP服務(wù)器端同時和多個客戶端通信
- Java利用TCP協(xié)議實現(xiàn)客戶端與服務(wù)器通信(附通信源碼)
- java Tcp通信客戶端與服務(wù)器端實例
- java模擬TCP通信實現(xiàn)客戶端上傳文件到服務(wù)器端
- Python socket網(wǎng)絡(luò)編程TCP/IP服務(wù)器與客戶端通信
- C#基于TCP協(xié)議的服務(wù)器端和客戶端通信編程的基礎(chǔ)教程
相關(guān)文章
CentOS服務(wù)器+Win客戶端安裝部署遠程控制RustDesk教程
RustDesk是一個開源的遠程控制項目,支持自建服務(wù)器以替代免費公共中繼服務(wù),本文詳細介紹了RustDesk服務(wù)端和客戶端的部署方法,包括在CentOS?7上部署服務(wù)端和Windows、Web客戶端的安裝步驟,同時,還探討了一些優(yōu)化建議2025-12-12
git安裝步驟_動力節(jié)點Java學(xué)院整理
這篇文章主要為大家詳細介紹了git安裝步驟的相關(guān)教程,Linux上安裝Git、Mac OS X上安裝Git,以及Windows上安裝Git,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
基于BaseHTTPRequestHandler的HTTP服務(wù)器使用及實現(xiàn)方法
BaseHTTPRequestHandler是Python中的一個基類,屬于http.server模塊,用于處理HTTP請求的基本功能,下面詳細介紹BaseHTTPRequestHandler的主要特點和使用方法,感興趣的朋友一起看看吧2023-10-10
安裝內(nèi)網(wǎng)穿透工具cpolar將本地運行的OpenClaw突破局域網(wǎng)限制實現(xiàn)隨時訪問
如何利用內(nèi)網(wǎng)穿透工具cpolar,將本地運行的OpenClaw AI服務(wù)映射至公網(wǎng),突破局域網(wǎng)限制實現(xiàn)隨時訪問,以及在外遠程控制家中電腦,操作步驟簡單,無需專業(yè)網(wǎng)絡(luò)知識,只需安裝cpolar并與OpenClaw交互即可完成配置,讓強大的本地AI服務(wù)真正實現(xiàn)"隨叫隨到"2026-03-03
Centos7使用docker搭建gitlab服務(wù)器
這篇文章主要為大家詳細介紹了Centos7使用docker搭建gitlab服務(wù)器,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-04-04

