首先写一个TCP.hpp的准备文件
#ifndef TCP_HPP
#define TCP_HPP
#include <iostream>
#include <cstring>
extern "C"
{
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
}
//设置套接字为非阻塞模式
int setNonBlocking(int &sockfd)
{
//获取套接字当前状态 获取状态
int flags = fcntl(sockfd, F_GETFL, 0);
if (flags == -1)
{
return -1;
}
//将表示非阻塞模式的那一个标志位设置为1
flags |= O_NONBLOCK;
// 设置状态
if (fcntl(sockfd, F_SETFL, flags) == -1)
{
return -1;
}
return 0;
}
class socketSend
{
public:
bool running;
socketSend(int fd) : client_fd(fd), running(true) {}
void sendData() // 发送数据
{
char buf[1024]{};
while (running)
{
memset(buf, 0, sizeof(buf));
if (fgets(buf, sizeof(buf), stdin) == nullptr)
continue;
buf[strcspn(buf, "\n")] = '\0'; // 结束符替换换行符
if (send(client_fd, buf, strlen(buf), 0) == -1)
{
perror("send()");
continue;
}
if (strcmp(buf, "exit") == 0)
{
running = false;
break;
}
}
}
private:
int client_fd;
};
void *sendDataHelper(void *arg)//发送数据
{
socketSend *c1 = (socketSend *)arg;
c1->sendData();
return nullptr;
}
#endif
服务端代码
#include "TCP.hpp"
using namespace std;
int main(int argc, const char *argv[])
{
if (argc != 2)
{
cout << "需要传入端口号" << endl;
return -1;
}
// 创建套接字
int server_fd = socket(PF_INET, SOCK_STREAM, 0);
if (server_fd == -1)
{
perror("socket()");
return -1;
}
// 设置服务端ip和端口
sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 主机字节序=>网络字节序
serverAddr.sin_port = htons(atoi(argv[1])); // 字符串=>整数=>16位网络字节序二进制值
// 绑定套接字
if (bind(server_fd, (sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
{
perror("bind()");
close(server_fd);
return -1;
}
// 设置监听
if (listen(server_fd, 5) == -1)
{
perror("listen()");
close(server_fd);
return -1;
}
cout << "等待连接......" << endl;
// 接收连接
sockaddr_in clientAddr;
memset(&clientAddr, 0, sizeof(sockaddr_in));
socklen_t len = sizeof(clientAddr);
int client_fd = accept(server_fd, (sockaddr *)&clientAddr, &len);
if (client_fd == -1)
{
perror("accept()");
close(client_fd);
close(server_fd);
return -1;
}
// 32位二进制网络字节序=>点分十进制字符串 0x7F000001=>“127.0.0.1”
cout << "ip: " << inet_ntoa(clientAddr.sin_addr) << " 端口: "
// 16位二进制网络字节序=>主机字节序 0x1234=>4660
<< ntohs(clientAddr.sin_port) << " 已连接到服务器!" << endl;
setNonBlocking(client_fd); // 设置套接字为非阻塞
socketSend c1(client_fd);
pthread_t t1;
pthread_create(&t1, nullptr, sendDataHelper, &c1);
char msg[1024]{};
while (c1.running) // 读
{
memset(msg, 0, sizeof(msg));
if (recv(client_fd, msg, sizeof(msg), 0) == -1)
{
continue;
}
cout << "来自客户端:" << msg << endl;
if (strcmp(msg, "exit") == 0)
break;
}
pthread_cancel(t1);
pthread_join(t1, nullptr);
// 关闭套接字
close(client_fd);
close(server_fd);
}
客户端代码
#include "TCP.hpp"
using namespace std;
int main(int argc, char *argv[])
{
if (argc != 3)
{
cerr << "请传入服务器的ip和port!" << endl;
return -1;
}
// 创建套接字
int client_fd = socket(PF_INET, SOCK_STREAM, 0);
if (client_fd < 0)
{
perror("sock()");
return -1;
}
// 设置服务端信息
sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(argv[1]); // 字符串=>32位网络字节序二进制值
serverAddr.sin_port = htons(atoi(argv[2])); // 字符串=>整数=>16位网络字节序二进制值
// 发起连接
if (connect(client_fd, (sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)
{
perror("connect()");
close(client_fd);
return -1;
}
setNonBlocking(client_fd);// 设置套接字为非阻塞
socketSend s1(client_fd);
pthread_t t1;
pthread_create(&t1, nullptr, sendDataHelper, &s1);
char msg[1024]{};
while (s1.running)//读
{
memset(msg, 0, sizeof(msg));
if (recv(client_fd, msg, sizeof(msg), 0) == -1)
{
continue;
}
cout << "来自服务端:" << msg << endl;
if (strcmp(msg, "exit") == 0)
break;
}
pthread_cancel(t1);
pthread_join(t1, nullptr);
// 关闭套接字
close(client_fd);
}
运行结果
任意一方输入exit,结束连接