Hike News
Hike News

[C++] Cpp socket通信

C++ Boost.Asio实现Socket局域网通信

需要的头文件:

1
2
3
4
5
#include <iostream>       // 输入输出
#include <fstream> // 文件操作
#include <string> // 字符串操作
#include <filesystem> // 文件操作
#include <boost/asio.hpp> // socket通信

笔记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tcp::resolver resolver = tcp::resolver(context);           // 解析器
tcp::endpoint ep = *resolver.resolve("127.0.0.1", "5555"); // 解析域名
tcp::resolver resolver(io); // 解析器
tcp::resolver::query q("www.baidu.com", "https"); // 查询
tcp::resolver::iterator eq2 = resolver.resolve(q); // 迭代器
tcp::endpoint ep = *resolver.resolve("127.0.0.1", "5555"); // 解析域名
tcp::resolver resolver(io); // 解析器
tcp::resolver::query q("www.baidu.com", "https"); // 查询
tcp::resolver::iterator eq2 = resolver.resolve(q); // 迭代器
sock.send(...); // 发送数据
sock.write_some(boost::asio::buffer("hello world", sizeof("hello world")));
sock.async_send(...); // 异步
io_context.run();
是一个成员函数,它的作用是启动异步操作的处理循环
sock.shutdown(tcp::socket::shutdown_both); // 关闭连接

客户端源代码:

预处理和命名空间:

1
2
3
4
5
6
// send.cpp
#define PORT 5555
#define BUF_SIZE 1024
#define Error -1
using namespace std;
using boost::asio::ip::tcp;

发送文件函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int send_file(tcp::socket &sock, std::string filename)
{
std::ifstream file(filename, std::ios::binary);
if (!file)
return Error;
char buffer[BUF_SIZE]; // 分配内存
while (file)
{
file.read(buffer, BUF_SIZE); // 读取文件
if (file.gcount() < BUF_SIZE)
{
sock.send(boost::asio::buffer(buffer, file.gcount()));
return 0;
}
sock.send(boost::asio::buffer(buffer, BUF_SIZE));
}
return 0;
}

参数解析函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int Parameter_parsing(int argc, char **argv, string &FilenameOrMsg, int &Is_File, boost::asio::ip::address &ip)
{
if (argc != 3)
return Error;
else
{
boost::asio::ip::address _ip;
boost::system::error_code ec;
_ip = boost::asio::ip::address::from_string(argv[1], ec);
if (ec)
return Error;
ip = _ip;
FilenameOrMsg = string(argv[2]);
if (filesystem::exists(FilenameOrMsg) && filesystem::is_regular_file(FilenameOrMsg))
Is_File = 1;
return 1;
}
}

主函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int main(int argc, char **argv)
{
try
{

boost::asio::io_context io_context;
tcp::socket sock(io_context);
boost::asio::ip::address TargetIp;
string FilenameOrMsg;
string &FileName = FilenameOrMsg;
string &Msg = FilenameOrMsg;
int Is_File = 0;
if (Parameter_parsing(argc, argv, FilenameOrMsg, Is_File, TargetIp) == Error)
{
// 输出提示
cout << "Usage: ./send <ip> <filename or message>" << endl;
return -1;
}
sock.connect(tcp::endpoint(TargetIp, PORT));
if (Is_File)
{
string _FileSize = std::to_string(std::filesystem::file_size(FileName));
string _FileName = filesystem::path(FilenameOrMsg).filename().string();
string _info = _FileName + '|' + _FileSize;
size_t _info_Size = _info.size();
char _info_Size_buffer[sizeof(size_t)];
memcpy(_info_Size_buffer, &_info_Size, sizeof(size_t));
char Mode[10] = "FILE MODE";
sock.send(boost::asio::buffer(Mode, 10));
sock.send(boost::asio::buffer(_info_Size_buffer, sizeof(size_t)));
sock.send(boost::asio::buffer(_info, _info_Size));
}
else
{
char Mode[10] = "MSGS MODE";
sock.send(boost::asio::buffer(Mode, 10));
size_t _Msg_Size = Msg.size();
char _Msg_Size_buffer[sizeof(size_t)];
memcpy(_Msg_Size_buffer, &_Msg_Size, sizeof(size_t));
int len = sock.send(boost::asio::buffer(_Msg_Size_buffer, sizeof(size_t)));
}
char confirm_send = 0;
sock.read_some(boost::asio::buffer(&confirm_send, sizeof(char)));
if (Is_File)
if (confirm_send || sock.is_open())
send_file(sock, FileName);
else
cout << "对方已拒绝接受文件!" << endl;
else
sock.send(boost::asio::buffer(Msg, Msg.size()));
sock.close();
}
catch (const boost::system::system_error &e)
{
cout << "无法链接至目标主机!" << '\n';
}
return 0;
}

服务端源代码:

确认文件是否接收函数:

1
2
3
4
5
6
7
8
9
10
11
12
bool Confirm(string FileName, size_t FileSize)
{
cout << "文件名: " << FileName << endl;
cout << "文件大小: " << FileSize << endl;
cout << "是否接收文件(Y/N): ";
char ch;
cin >> ch;
if (ch == 'Y' || ch == 'y')
return 1;
else
return 0;
}

接收文件函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
int recv_file(tcp::socket &sock, std::string &file_name)
{
std::ofstream ofs(file_name, std::ios::binary);
char buf[BUF_SIZE];
while (true)
{
int len = sock.read_some(boost::asio::buffer(buf, BUF_SIZE));
ofs.write(buf, len);
if (len < BUF_SIZE)
break;
}
return OK;
};

主函数部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
int main(void)
{
cout << "开始接收数据!" << endl;
boost::asio::io_context context;
tcp::socket sock(context);
tcp::endpoint ep(boost::asio::ip::address::from_string("0.0.0.0"), PORT);
tcp::acceptor acceptor(context, ep);
acceptor.accept(sock);
char Mode[10] = "FILE MODE";
string FileName;
size_t FileSize;
size_t InfoSize;
sock.read_some(boost::asio::buffer(Mode, 10));
// 将整数转换为字节流并存储到字符数组中
char _InfoSize_buf[sizeof(size_t)];
sock.read_some(boost::asio::buffer(_InfoSize_buf, sizeof(size_t)));
std::memcpy(&InfoSize, _InfoSize_buf, sizeof(size_t));
if (!strcmp("FILE MODE", Mode))
{
char _File_NameSzie[InfoSize + 1];
int Index = 0;
int len = sock.read_some(boost::asio::buffer(_File_NameSzie, InfoSize));
_File_NameSzie[len] = '\0';
for (auto &c : _File_NameSzie)
{
Index++;
if (c == '|')
{
string _StrT_FileSize = string(_File_NameSzie).substr(Index, InfoSize);
FileSize = stoi(_StrT_FileSize);
break;
}
FileName = FileName + c;
}
if (Confirm(FileName, FileSize))
{
char Is_Confirm = 1;
sock.send(boost::asio::buffer(&Is_Confirm, sizeof(char)));
recv_file(sock, FileName);
cout << "文件接收成功!" << endl;
}
else
return 0;
}
else
{
cout << "来自 " << sock.remote_endpoint().address() << " 的消息: " << endl;
char confirm_send = 0;
sock.send(boost::asio::buffer(&confirm_send, sizeof(char)));
char _Msg_buf[InfoSize + 1];
int len = sock.read_some(boost::asio::buffer(_Msg_buf, InfoSize));
_Msg_buf[len] = '\0';
cout << _Msg_buf << endl;
}
sock.close();
return 0;
}