最近在研究windows sock
dev c++跑起来后
打印了:
Connected to server
Error receiving data: 10057
客户端代码(隐蔽了服务器地址)
#include <Winsock2.h>
#include <iostream>
#include <string>
#include <conio.h>
#pragma comment(lib, "ws2_32.lib") //链接到winsock库
using namespace std;
int main()
{
// 初始化 Winsock 库
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) {
cerr << "Error initializing socket library" << endl;
return 1;
}
// 创建用于通信的套接字
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd == INVALID_SOCKET) {
cerr << "\nSocket creation failed: "<< WSAGetLastError() << endl;
WSACleanup();
return 1;
}
// 将套接字设置为非阻塞模式
unsigned long blocking_mode = 1; // 0=non-blocking, 1=blocking mode
if (ioctlsocket(sockfd, FIONBIO, &blocking_mode) != NO_ERROR) {
cerr << "\nFailed to set non-blocking mode" << endl;
closesocket(sockfd);
WSACleanup();
return 1;
}
// 获取要连接的主机和端口号,这里以localhost为例
string host = "43.138.236.72"; //localhost
int port = 1160;
// 连接服务器
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(host.c_str());
int connect_result = connect(sockfd, (sockaddr *)&server_addr, sizeof(server_addr));
if (connect_result == SOCKET_ERROR) {
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS) {
// 连接正在进行中,这是正常行为
} else {
cerr << "\nFailed to connect: " << err << endl;
closesocket(sockfd);
WSACleanup();
return 1;
}
}
cout << "\nConnected to server" << endl;
string input;
while(true) {
// 检查是否有来自服务器的新消息
char buffer[1024];
int recv_len = recv(sockfd, buffer, sizeof(buffer), 0);
if (recv_len > 0) {
buffer[recv_len] = '\0'; // 在结尾添加 null 字符以便于打印字符串
cout <<"\nServer says: " << buffer << endl;
cout<<input;
} else {
int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) {
cerr << "\nError receiving data: " << err << endl;
break;
}
}
// 从标准输入读取信息并向服务器发送
if(_kbhit())
{
char ch;
ch=_getch();
if(cin.fail()) { // 如果无法读取输入,则表示用户已经通过Ctrl+Z或Ctrl+C退出
break;
}
if(ch)
{
if(ch=='\n')
{
int send_len = send(sockfd, input.c_str(), input.length(), 0);
if (send_len == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS)
{
cerr << "\nFailed to send data: ";
}
}
input.clear();
}
else
{
input=+ch;
}
}
}
}
}
服务端:
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <fcntl.h>
using namespace std;
int main() {
// 创建Socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("Failed to create socket");
return -1;
}
// 绑定地址和端口号
sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // IPv4协议族
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 自动获取IP地址
server_addr.sin_port = htons(1160); // 端口号为12345
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {//绑定套接字
perror("Failed to bind socket");
close(sockfd);
return -1;
}
// 开始监听
if (listen(sockfd, 2) < 0) { //监听 二三参分别为创建套接字,允许建立连接队列长度。
perror("Failed to listen on socket");
close(sockfd);
return -1;
}
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags|O_NONBLOCK);//设置为非阻塞模式
// 创建用于accept的变量,接受客户端连接
int client_sockfd[2] = {0,0};
sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
int connected_clients = 0;
cout<<"server ok"<<endl;
while (connected_clients < 2) {
fd_set readset;
FD_ZERO(&readset);
FD_SET(sockfd, &readset);
struct timeval tv;
tv.tv_sec = 0.1; // 超时时间为0.1秒
tv.tv_usec = 0;
int ret = select(sockfd + 1, &readset, NULL, NULL, &tv); //在select函数阻塞期间内核会持续监控输入参数中描述符上的读事件是否发生
if(connected_clients!=0)
{
if (ret == -1) { //错误处理
perror("Failed to select on socket");
return -1;
} else if (ret == 0) { //超时处理
printf("Timeout occurred. There are %d clients connected.\n", connected_clients);
continue;// 回到while循环开始等待新的套接字连接
}
// 如果有客户端发起了连接请求
if (FD_ISSET(sockfd, &readset)) {
int new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &length); //接受客户端连接,返回一个新的socket描述符
if (new_sockfd < 0) { //错误处理
perror("Failed to accept socket");
} else {
printf("Client %d connected.\n", connected_clients+1);
client_sockfd[connected_clients] = new_sockfd;//保存客户端套接字描述符
connected_clients++;
if(connected_clients==1)
{
continue;
}
}
}
}
}
// 接收和转发消息
while (true) {
fd_set readset;
FD_ZERO(&readset);//清空集合
for (int i = 0; i < 2; i++) {
FD_SET(client_sockfd[i], &readset);//将两个客户端的描述符加入监听集合
}
struct timeval tv;
tv.tv_sec = 0.1; // 超时时间为0.1秒
tv.tv_usec = 0;
int ret = select(client_sockfd[1] + 1, &readset, NULL, NULL, &tv); //在select函数阻塞期间内核会持续监控输入参数中描述符上的读事件是否发生
if (ret == -1) { //错误处理
perror("Failed to select on socket");
break;
} else if (ret == 0) { //超时处理
printf("Timeout occurred. Waiting for new messages...\n");
continue;
}
// 如果有客户端发送了新消息
for (int i = 0; i < 2; i++) {
if (FD_ISSET(client_sockfd[i], &readset)) {
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
int len = recv(client_sockfd[i], buffer, sizeof(buffer), 0);
if (len <= 0) { //连接关闭
printf("Client %d closed.\n", i+1);
close(client_sockfd[i]);
client_sockfd[i] = 0;
} else {
printf("Received from client %d: %s", i+1, buffer);
if (i == 0 && client_sockfd[1] != 0) { //转发给另一个客户端
send(client_sockfd[1], buffer, strlen(buffer), 0);
} else if (i == 1 && client_sockfd[0] != 0) {
send(client_sockfd[0], buffer, strlen(buffer), 0);
}
}
}
}
}
// 关闭套接字
for (int i = 0; i < 2; i++) {
if (client_sockfd[i] != 0) {
close(client_sockfd[i]);
}
}
close(sockfd);
return 0;
}