本帖最后由 YFSafe 于 2022-5-31 19:11 编辑
有些时候本人会用到双人通讯,苦于没有可用软件,于是自己开发一个。
一: 思路
使用socket套接字编写双方程序。
socket简介(来源百度百科):
socket用于在两个的应用程序之间相互通信,socket是属于TCP\IP的上一层。最早出现在UNIX系统中,是UNIX系统主要的信息传递方式。在WINDOWS系统中,SOCKET称为WINSOCK。两个基本概念:客户方和服务方。当两个应用之间需要采用SOCKET通信时,首先需要在两个应用之间(可能位于同一台机器,也可能位于不同的机器)建立SOCKET连接,发起呼叫连接请求的一方为客户方,接受呼叫连接请求的一方成为服务方。客户方和服务方是相对的,同一个应用可以是客户方,也可以是服务方。在客户方呼叫连接请求之前,它必须知道服务方在哪里。所以需要知道服务方所在机器的IP地址或机器名称,如果客户方和服务方事前有一个约定就好了,这个约定就是PORT(端口号)。也就是说,客户方可以通过服务方所在机器的IP地址或机器名称和端口号唯一的确定方式来呼叫服务方。在客户方呼叫之前,服务方必须处于侦听状态,侦听是否有客户要求建立连接。一旦接到连接请求,服务方可以根据情况建立或拒绝连接。连接方式有两种,同步方式(Blocking)和异步方式(noBlocking)。客户方发送的消息可以是文本,也可以是二进制信息流。当客户方的消息到达服务方端口时,会自动触发一个事件(event),服务方只要接管该事件,就可以接受来自客户方的消息了。
二:代码实现
Server:
[C++] 纯文本查看 复制代码 #include<iostream>
#include<winsock.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字库失败!" << endl;
}
else {
cout << "初始化套接字库成功!" << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
else {
cout << "套接字库版本正确!" << endl;
}
int send_len = 0;
int recv_len = 0;
int len = 0;
char send_buf[10005];
char recv_buf[10005];
SOCKET s_server;
SOCKET s_accept;
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
initialization();
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(22);
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (bind(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << "套接字绑定失败!" << endl;
WSACleanup();
}
else {
cout << "套接字绑定成功!" << endl;
}
if (listen(s_server, SOMAXCONN) < 0) {
cout << "设置监听状态失败!" << endl;
WSACleanup();
}
else {
cout << "设置监听状态成功!" << endl;
}
cout << "服务端正在监听连接,请稍候...." << endl;
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR *)&accept_addr, &len);
if (s_accept == SOCKET_ERROR) {
cout << "连接客户端失败!" << endl;
WSACleanup();
return 0;
}
cout << "连接已建立" << endl;
while (1) {
recv_len = recv(s_accept, recv_buf, 10005, 0);
if (recv_len < 0) {
cout << "接受客户端信息失败!" << endl;
break;
}
else {
cout << "客户端发送的信息:" << recv_buf << endl;
}
cout << "请输入回复信息:";
cin >> send_buf;
send_len = send(s_accept, send_buf, 10005, 0);
if (send_len < 0) {
cout << "恢复失败!" << endl;
break;
}
}
closesocket(s_server);
closesocket(s_accept);
WSACleanup();
return 0;
}
Client:
[C++] 纯文本查看 复制代码 #include<iostream>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main()
{
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << "初始化套接字库失败!" << endl;
}
else {
cout << "初始化套接字库成功!" << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
else {
cout << "套接字库版本正确!" << endl;
}
int send_len = 0;
int recv_len = 0;
char send_buf[10005];
char recv_buf[10005];
SOCKET s_server;
SOCKADDR_IN server_addr;
initialization();
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(/*这里填你的内网ip地址*/);
server_addr.sin_port = htons(22);
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << "连接服务端失败!" << endl;
WSACleanup();
}
else {
cout << "成功连接至服务端!" << endl;
}
while (1) {
cout << "请输入要发送信息:";
cin >> send_buf;
send_len = send(s_server, send_buf, 10005, 0);
if (send_len < 0) {
cout << "发送信息失败!" << endl;
}
recv_len = recv(s_server, recv_buf, 10005, 0);
if (recv_len < 0) {
cout << "接受服务端信息失败!" << endl;
}
else {
cout << "服务端信息:" << recv_buf << endl;
}
}
//关闭套接字
closesocket(s_server);
//释放DLL资源
WSACleanup();
return 0;
}
本程序在Devc++ 5.11 Windows 10 编译成功。
3.检验成果
|