客户端代码
//IO多路复用技术select函数的使用
#include<iostream>
#include<winsock.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
void initialization();
int main()
{
initialization();
int ret;
SOCKET cfd;
SOCKADDR_IN srvAddr;
char buf[FD_SETSIZE];
cfd = socket(AF_INET, SOCK_STREAM, 0);
if (cfd < 0)
{
perror("socket error");
}
memset(&srvAddr, 0, sizeof(srvAddr));
srvAddr.sin_family = AF_INET;
srvAddr.sin_port = htons(8888);
srvAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
//连接
ret = connect(cfd, (SOCKADDR*)&srvAddr, sizeof(srvAddr));
if (ret == SOCKET_ERROR)
{
cout << "connect error" << endl;
}
while (1)
{
memset(buf, 0, sizeof(buf));
cout << "请输入内容:";
cin >> buf;
send(cfd, buf, sizeof(buf), 0);
memset(buf, sizeof(buf), 20);
recv(cfd, buf, 20, 0);
//cout << "接收到的信息:" << buf << endl;
printf("%s\n", buf);
}
//关闭监听文件描述符
closesocket(cfd);
WSACleanup();
system("pause");
return 0;
}
void initialization()
{
WORD w_req = MAKEWORD(2, 2);
WSADATA wsadata;
if (WSAStartup(w_req, &wsadata) != 0)
{
cout << "初始化套接字失败" << endl;
}
else
{
cout << "初始化套接字成功" << endl;
}
}
服务端代码
//IO多路复用技术select函数的使用
#include<iostream>
#include<winsock.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
void initialization();
int main()
{
initialization();
int i;//for循环因子
int ret;//bind和listen返回值
int nready;//select返回值
int len;//accept中cliaddrd的地址
int rlen;//recv读取的字符长度
char buf[FD_SETSIZE];
fd_set tmpfds, rdfds; //要监控的文件描述符集
SOCKET lfd, cfd;//socket和accept返回值
SOCKADDR_IN svraddr, cliaddr;
//创建socket
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd < 0)
{
perror("socket error");
return -1;
}
//允许端口复用
int opt = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(int));
//绑定bind
memset(&svraddr, 0, sizeof(svraddr));
svraddr.sin_family = AF_INET;
svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
svraddr.sin_port = htons(8888);
ret = bind(lfd, (SOCKADDR*)&svraddr, sizeof(svraddr));
if (ret < 0)
{
perror("bind error");
return -1;
}
//监听listen
ret = listen(lfd, 5);
if (ret < 0)
{
perror("listen error");
return -1;
}
//文件描述符集初始化
FD_ZERO(&tmpfds);
FD_ZERO(&rdfds);
//将lfd加入到监控的读集合中
FD_SET(lfd, &rdfds);
//将监听文件描述符lfd加入到select监控中
while (1)
{
//select为阻塞函数,若没有变化的文件描述符,就一直阻塞,若有事件发生则解除阻塞,函数返回
//select的第二个参数tmpfds为输入输出参数,调用select完毕后这个集合中保留的是发生变化的文件描述符
tmpfds = rdfds;
nready = select(0, &tmpfds, NULL, NULL, NULL);
if (nready <= 0)
{
continue;
}
memset(&cliaddr, 0, sizeof(svraddr));
//发生变化的文件描述符有两类, 一类是监听的, 一类是用于数据通信的
//监听文件描述符有变化, 有新的连接到来, 则accept新的连接
for (i = 0; i < rdfds.fd_count; i++)
{
if (FD_ISSET(rdfds.fd_array[i], &tmpfds))
{
if (rdfds.fd_array[i] == lfd)
{
len = sizeof(cliaddr);
cfd = accept(lfd, (SOCKADDR*)&cliaddr, &len);
if (cfd < 0)
{
if (errno == ECONNABORTED || errno == EINTR)
{
continue;
}
break;
}
cout << "connect success" << endl;
//将新的文件 描述符加入到select监控的文件描述符集合中
FD_SET(cfd, &rdfds);
}
else//下面是通信的文件描述符有变化的情况
{
rlen = recv(rdfds.fd_array[i], buf, FD_SETSIZE, 0);
if (rlen == 0)
{
FD_CLR(rdfds.fd_array[i], &rdfds);
closesocket(tmpfds.fd_array[i]);
}
else
{
cout <<"server:"<< buf << endl;
for (i = 0; i < rlen; i++)
{
buf[i] = toupper(buf[i]);
}
send(rdfds.fd_array[i], buf, rlen, 0);
cout << "已发送:" << buf << endl;
}
closesocket(rdfds.fd_array[i]);
}
}
}
}
//关闭监听文件描述符
closesocket(lfd);
WSACleanup();
return 0;
}
void initialization()
{
WORD w_req = MAKEWORD(2, 2);
WSADATA wsadata;
if (WSAStartup(w_req, &wsadata) != 0)
{
cout << "初始化套接字失败" << endl;
}
else
{
cout << "初始化套接字成功" << endl;
}
}