C++socket一些异常的情况(断网下recv/send,对方close socket后执行recv/send等)
先介绍一下实验的一些配置情况。server和client部署在同一台主机上(太穷了,凑不齐两台)。server在windows上,client在Ubuntu上。
socket设置为阻塞模式。
实验1:server的和client连接的socket被close后,client进行recv
结果:recv返回0
如图:
client端:
实验2:server的和client连接的socket被close后,client向server进行send
结果:send的第一条消息正常返回,send第二条时程序直接退出,退出码为141(?没查到这是什么意思)
如图:
client端:
//有点疑惑哈,close对应的应该不是两次挥手。挥手是不可发但可读,但是你都不允许对方进行send,那怎么读?
实验3:client和server均断网条件下client向server进行send,server进行recv
结果:断网时,client每一次send都正常返回,server的recv一直阻塞;恢复网络后,server会收到之前client在断网条件下发送的所有消息
如图:
//很奇怪,手动断开网络后第一条消息仍然能够被server接收到,后面断开网络后又等了一两分钟再进行send,还是一样的结果
推测:send只是把数据拷贝到缓冲区,并不会阻塞到等待对方进行ACK再返回(当然如果发送缓冲区满了应该还是要阻塞能够到把数据放到发送缓冲区)
实验代码
server
#include <stdio.h>
#include <winsock2.h>
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
#define PORT 65432
#define SERVERIP "xx.xx.xx.xx" //设置成你自己的ip
using namespace std;
int main()
{
//初始化WSA
WORD sockVersion = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData)!=0){
return 0;
}
//创建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(slisten == INVALID_SOCKET){
printf("socket error !");
return 0;
}
//绑定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT); //
//sin.sin_addr.S_un.S_addr = INADDR_ANY;
sin.sin_addr.s_addr=inet_addr(SERVERIP);
if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){
printf("bind error !");
}
//开始监听
if(listen(slisten, 5) == SOCKET_ERROR){
printf("listen error !");
return 0;
}
//循环接收数据
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
printf("等待连接...\n");
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
if(sClient == INVALID_SOCKET){
printf("accept error !");
return 0;
}
printf("接受到连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
while (true){
//接收数据
cout<<"接收消息中:";
int ret = recv(sClient, revData, 255, 0);
if(ret > 0){
revData[ret] = 0x00;
printf(revData);
cout<<" 接收消息完成"<<endl;
}
else{
printf("连接断开\n");
}
}
closesocket(sClient);
closesocket(slisten);
WSACleanup();
return 0;
}
client
#include <iostream>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define SERVER_IP "xx.xx.xx.xx" //换成server的IP
#define PORT 65432
using namespace std;
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[1024] = {0};
// 创建 socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
std::cerr << "Socket creation error" << std::endl;
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// 转换 IPv4 和 IPv6 地址从文本到二进制
if (inet_pton(AF_INET,SERVER_IP, &serv_addr.sin_addr) <= 0) {
std::cerr << "Invalid address/ Address not supported" << std::endl;
return -1;
}
cout<<"准备连接"<<endl;
// 连接到服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
std::cerr << "Connection failed" << std::endl;
return -1;
}
cout<<"连接成功"<<endl;
char message[255]; // 存储用户输入的消息
memset(message, 0, sizeof(message));
while(true){
memset(message, 0, sizeof(message));
std::cout << "请输入要发送的消息: ";
std::cin >> message;
int sendresult=send(sock,message,255,0);
cout<<"send result: "<<sendresult<<endl;
}
// 关闭 socket
close(sock);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架