一. 服务端和客户端服务流程图
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d0e06c6607629a29462df99afebba6db.png)
二. 服务端的实现
1.1 服务端和客户端公用文件tcpSocket.h, tcpSocket.cpp
#ifndef _TCPSOCKET_H_
#define _TCPSOCKET_H
#include<WinSock2.h>
#include<WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#include<stdbool.h>
#include<stdio.h>
#define PORT 8899
#define err(errMsg) printf("[line:%d] %s failed code %d\n", __LINE__, errMsg, WSAGetLastError());
bool init_Socket();
bool close_Socket();
bool sendMsg(int fd, const char* msg);
bool recvMsg(int fd, char* buf, int bufSize);
#endif
#include "tcpSocket.h"
bool init_Socket()
{
WSADATA wsadata;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsadata)) {
err("WSAStartup");
return false;
}
return true;
}
bool close_Socket()
{
if (0 != WSACleanup()) {
err("WSACleanup");
return false;
}
return true;
}
bool sendMsg(int fd, const char* msg) {
int ret = send(fd, msg, strlen(msg) + 1, 0);
if (ret == -1) {
err("send msg");
return false;
}
return true;
}
bool recvMsg(int fd, char* buf, int bufSize) {
int len = recv(fd, buf, bufSize, 0);
if (len > 0) {
printf("服务端说: %s\n", buf);
return true;
}
else if (len == 0)
{
printf("服务器端已经断开了...\n");
}
else {
perror("recv");
}
return false;
}
1.2 服务端主程序 server.cpp
#include "../tcpSocket/tcpSocket.h"
#include <thread>
struct SockInfo {
sockaddr_in addr;
int fd;
};
void* working(SockInfo *pinfo);
SockInfo infos[512] = { 0 };
int main() {
init_Socket();
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1)
{
err("socket");
return -1;
}
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
saddr.sin_addr.S_un.S_addr = INADDR_ANY;
int ret = bind(fd, (sockaddr*)&saddr, sizeof(saddr));
if (ret == -1) {
err("bind");
return -1;
}
ret = listen(fd, 10);
if (ret == -1)
{
err("listen");
return -1;
}
printf("等待客户端连接...\n");
int max = sizeof(infos) / sizeof(infos[0]);
for (int i = 0; i < max; ++i)
{
infos[i].fd = -1;
}
int addrLen = sizeof(sockaddr_in);
while (1) {
SockInfo* pinfo = nullptr;
for (int i = 0; i < max; ++i)
{
if (infos[i].fd == -1) {
pinfo = &infos[i];
break;
}
}
int cfd = accept(fd, (struct sockaddr*)&pinfo->addr, &addrLen);
if (cfd == -1) {
err("accept");
break;
}
pinfo->fd = cfd;
std::thread Worker(working, pinfo);
Worker.detach();
}
closesocket(fd);
close_Socket();
return 0;
}
void* working(SockInfo *pinfo)
{
char ip[32];
printf("客户端fd: %d, IP:%s, 端口:%d\n",
pinfo->fd,
inet_ntop(AF_INET, &pinfo->addr.sin_addr.S_un, ip, sizeof(ip)),
ntohs(pinfo->addr.sin_port)
);
while (1) {
char buf[1024];
if (recvMsg(pinfo->fd, buf, sizeof(buf))) {
sendMsg(pinfo->fd, buf);
}
}
int ret = closesocket(pinfo->fd);
if (ret == 0)
{
printf("释放客户端fd:%d\n", pinfo->fd);
}
pinfo->fd = -1;
return NULL;
}
三 客户端的实现
3.1 客户端主程序 client.cpp
#include <iostream>
#include "../tcpSocket/tcpSocket.h"
int main()
{
init_Socket();
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1)
{
err("socket");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.S_un.S_addr);
int ret = connect(fd, (sockaddr*)&addr, sizeof(addr));
if ( ret == -1)
{
err("connect");
return -1;
}
int number = 0;
while (1) {
sendMsg(fd, "你好,我是客户端");
char recvBuf[BUFSIZ];
memset(recvBuf, 0, sizeof(recvBuf));
if (!recvMsg(fd, recvBuf, sizeof(recvBuf))){
break;
}
printf("接收到的消息:%s\n", recvBuf);
Sleep(1000);
}
closesocket(fd);
close_Socket();
return 0;
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d23e871dbd6b0f07edf2be052dea57bb.png)
C++ 实现socket通讯
服务端和客户端公用文件tcpSocket.h, tcpSocket.cpp
#ifndef _TCPSOCKET_H_
#define _TCPSOCKET_H_
#include <iostream>
#include <thread>
#include <map>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#define PORT 8899
class TcpSocket
{
public:
TcpSocket();
~TcpSocket();
public:
bool InitSocket();
bool CloseSocket();
void CreateSocket();
bool RecvMsg(int fd, char* buf, int bufSize);
bool SendMsg(int fd, const char* msg);
bool BindSocket();
bool ListenSocket(int clientNumber);
bool AcceptConnect();
void* ServerWorking(int cfd);
bool ConnectServerSocket();
void* ClientWorking();
void ShowError(const char* msg);
public:
int m_fd;
private:
std::map<int, sockaddr_in*> m_pClientSockInfo;
};
#endif
#include "TcpSocket.h"
bool TcpSocket::InitSocket()
{
WSADATA wsadata;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsadata)) {
ShowError("WSAStartup");
return false;
}
return true;
}
bool TcpSocket::CloseSocket()
{
if (0 != WSACleanup()) {
ShowError("WSACleanup");
return false;
}
return true;
}
void TcpSocket::CreateSocket()
{
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1) {
ShowError("socket create");
}
m_fd = fd;
}
bool TcpSocket::RecvMsg(int fd, char* buf, int bufSize)
{
int len = recv(fd, buf, bufSize, 0);
if (len > 0) {
return true;
}
else if (len == 0)
{
printf("fd:%d, 链接已经断开了...\n", fd);
}
else {
perror("recv");
}
return false;
}
bool TcpSocket::SendMsg(int fd, const char* msg)
{
if (-1 == send(fd, msg, strlen(msg) + 1, 0)) {
ShowError("send");
return false;
}
return true;
}
bool TcpSocket::BindSocket()
{
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
saddr.sin_addr.S_un.S_addr = INADDR_ANY;
if (-1 == bind(m_fd, (sockaddr*)&saddr, sizeof(saddr))) {
ShowError("bind");
return false;
}
return true;
}
bool TcpSocket::ListenSocket(int clientNumber)
{
if (-1 == listen(m_fd, clientNumber)) {
ShowError("listen");
return false;
}
return true;
}
bool TcpSocket::AcceptConnect()
{
int addrLen = sizeof(sockaddr_in);
while (1) {
printf("等待客户端连接...\n");
sockaddr_in* outAddr = new sockaddr_in;
int cfd = accept(m_fd, (struct sockaddr*)outAddr, &addrLen);
if (cfd == -1) {
ShowError("accept");
return false;
}
m_pClientSockInfo.insert(std::pair<int, sockaddr_in*>(cfd, outAddr));
char ip[32];
printf("客户端fd: %d, IP:%s, 端口:%d\n",
cfd,
inet_ntop(AF_INET, &m_pClientSockInfo.at(cfd)->sin_addr.S_un, ip, sizeof(ip)),
ntohs(m_pClientSockInfo.at(cfd)->sin_port)
);
printf("客户端数量:%d\n", m_pClientSockInfo.size());
SendMsg(cfd, "Welcome to ctp auto trade\n");
std::thread Worker(&TcpSocket::ServerWorking, this, cfd);
Worker.detach();
}
return true;
}
void* TcpSocket::ServerWorking(int cfd)
{
printf("Server Message: client cfd:%d connected\n", cfd);
while (1) {
char buf[1024];
if (RecvMsg(cfd, buf, sizeof(buf)) ) {
SendMsg(cfd, buf);
}
else {
break;
}
}
if (closesocket(cfd) == 0)
{
m_pClientSockInfo.erase(cfd);
printf("释放客户端fd:%d\n", cfd);
}
return nullptr;
}
bool TcpSocket::ConnectServerSocket()
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.S_un.S_addr);
if (-1 == connect(m_fd, (sockaddr*)&addr, sizeof(addr))) {
ShowError("connect");
return false;
}
std::thread ClientWork(&TcpSocket::ClientWorking, this);
ClientWork.detach();
return true;
}
void* TcpSocket::ClientWorking()
{
printf("Client Working\n");
while (1) {
char buf[512];
if (RecvMsg(m_fd, buf, sizeof(buf))) {
printf("Client Recv: %s\n", buf);
}
else {
printf("Client Recv: 服务端已经关闭\n");
break;
}
}
return nullptr;
}
void TcpSocket::ShowError(const char* msg)
{
printf("[line:%d] %s failed code %d\n", __LINE__, msg, WSAGetLastError());
}
TcpSocket::TcpSocket()
{
InitSocket();
}
TcpSocket::~TcpSocket()
{
CloseSocket();
}
服务端 server.cpp
#include <iostream>
#include "../tcpSocket/TcpSocket.h"
int main()
{
TcpSocket tcpSocket;
tcpSocket.CreateSocket();
tcpSocket.BindSocket();
tcpSocket.ListenSocket(100);
tcpSocket.AcceptConnect();
system("pause");
return 0;
}
客户端client.cpp
#include <iostream>
#include "../tcpSocket/TcpSocket.h"
int main()
{
TcpSocket tcpSocket;
tcpSocket.CreateSocket();
tcpSocket.ConnectServerSocket();
system("pause");
return 0;
}