以下是server端主要代码介绍
服务端:建立socket,申明自身port和IP,并绑定到socket,使用listen监听,
然后不断用accept查看是否有连接。如果有,捕获socket,并通过recv获取消息内容,
通信完成后调用closeSocket关闭accept捕获到的socket。如果不需要等待任何客户端连接,
直接用closeSocket关闭自身的socket。
1.初始化套接字
#include <winsock.h>
Winsock是Windows下的网络编程接口,winsock工作在应用层,它提供与底层传输协议无关的高层数据传输编程接口。
#pragma comment(lib,"ws2_32.lib")
扩展,把ws2_32.lib 这个库加入到工程文件中,提供了对网络相关API的支持
#include <winsock.h>//Winsock是Windows下的网络编程接口,winsock工作在应用层,它提供与底层传输协议无关的高层数据传输编程接口。
#pragma comment(lib,"ws2_32.lib") //扩展,把ws2_32.lib 这个库加入到工程文件中,提供了对网络相关API的支持
2.定义各种变量
定义长度变量;
定义发送缓冲区和接受缓冲区;
定义服务端套接字,接受请求套接字;
定义服务端地址 客户端地址。
int send_len = 0;
int recv_len = 0;//定义长度变量
int len = 0;
char send_buf[100];
char recv_buf[100];//定义发送缓冲区和接受缓冲区
SOCKET s_server;
SOCKET s_accept;//定义服务端套接字,接受请求套接字
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;//服务端地址 客户端地址
3.填充服务端各种信息,创建套接字
填充服务端地址信息,AF_INET 用于socket创建通信连接的类型,这里就是ipv4地址类型的通信连接可用;
将主机数转换成无符号长整形的网络字节顺序;
将整型变量从主机字节顺序转变成网络字节顺序;
创建套接字 socket(地址类型,套接字类型,传输协议)。
server_addr.sin_family = AF_INET;//填充服务端地址信息,AF_INET 用于socket创建通信连接的类型,这里就是ipv4地址类型的通信连接可用。
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //htonl()将主机数转换成无符号长整形的网络字节顺序
server_addr.sin_port = htons(5010); //htons()将整型变量从主机字节顺序转变成网络字节顺序
s_server = socket(AF_INET, SOCK_STREAM, 0); //创建套接字 socket(地址类型,套接字类型,传输协议)
4.绑定套接字到一个IP地址和一个端口上(bind()。
bind函数把一个本地协议地址赋予一个套接字。对于网际协议,协议地址是32位的IPv4地址或是128位的IPv6地址与16位的TCP或UDP端口号的组合。
如果我们使用cout,则必须在程序中使用命名空间std,或者如果您不使用std命名空间,则应该使用std::cout。
if (bind(s_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)//绑定套接字到一个IP地址和一个端口上(bind()),
//bind函数把一个本地协议地址赋予一个套接字。对于网际协议,协议地址是32位的IPv4地址或是128位的IPv6地址与16位的TCP或UDP端口号的组合。
{
std::cout << "套接字绑定失败!" << std::endl;//如果我们使用cout,则必须在程序中使用命名空间std,或者如果您不使用std命名空间,则应该使用std::cout。
closesocket(s_server);
WSACleanup();
return 0;
}
else
{
std::cout << "套接字绑定成功!" << std::endl;
}
5.将套接字设置为监听模式等待连接请求(listen())
if (listen(s_server, SOMAXCONN) < 0)
{
std::cout << "设置监听状态失败!" << std::endl;
closesocket(s_server);
WSACleanup(); //解除与Socket库的绑定并且释放Socket库所占用的系统资源
return 0;
}
else
{
std::cout << "设置监听状态成功!" << std::endl;
}
std::cout << "服务端正在监听中......" << std::endl;
6.请求到来后接受连接请求,返回一个新的对应于此次连接的套接字(accept())
while (true)
{
//请求到来后接受连接请求,返回一个新的对应于此次连接的套接字(accept())
len = sizeof(SOCKADDR);
s_accept = accept(s_server, (SOCKADDR*)&accept_addr, &len);
if (s_accept == SOCKET_ERROR)
{
std::cout << "连接失败!" << std::endl;
closesocket(s_server);
closesocket(s_accept);
WSACleanup();
return 0;
}
std::cout << "建立连接!准备接受数据。" << std::endl;
7.用返回的套接字和客户端进行通信(send()/recv())
while (true)
{
recv_len = recv(s_accept, recv_buf, 100, 0);
if (recv_len < 0)
{
std::cout << "接受失败!" << std::endl;
break;
}
else
{
std::cout << "客户端信息:" << recv_buf << std::endl;
}
if (strcmp(recv_buf, "bye") == 0)
{ //断开通信
std::cout << "本次通信结束!" << std::endl;
std::cout << "服务端正在监听中......" << std::endl;
break;
}
std::cout << "请输入回复信息:";
std::cin >> send_buf;
send_len = send(s_accept, send_buf, 100, 0);
if (send_len < 0)
{
std::cout << "发送失败!" << std::endl;
break;
}
//返回等待另一个连接请求
}
}
8. 关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())
closesocket(s_server);
closesocket(s_accept);
WSACleanup();
在此,server端代码结束,初始化套接字函数initialization()我没有给出,将在文末给出连接。
以下开始cilent端的代码详解。
客户端:建立socket,通过端口号和地址确定目标服务器,使用connect连接到服务器,
send发送消息,等待处理,通信完成后调用closeSocket关闭socket。
在此不仔细讲解已经在server端讲过的重复内容。
1.初始化
#include <winsock.h>
#pragma comment(lib,"ws2_32.lib") //扩展,把ws2_32.lib 这个库加入到工程文件中
void initialization();
2.定义各种变量,详情看代码注释
//定义长度变量
int send_len = 0;
int recv_len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[100];
//定义服务端套接字,接受请求套接字
SOCKET s_server;
//服务端地址
SOCKADDR_IN server_addr;
initialization();
//填充服务端地址信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(5010);
//创建套接字 socket(地址类型,套接字类型,传输协议)
s_server = socket(AF_INET, SOCK_STREAM, 0);
3.向服务器发出连接请求(connect())
if (connect(s_server, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
std::cout << "服务器连接失败!" << std::endl;
closesocket(s_server);
WSACleanup();
return 0;
}
else
{
std::cout << "服务器连接成功!" << std::endl;
}
4.和服务区进行通信(send()/recv())
while (true)
{
std::cout << "请输入发送信息:";
std::cin >> send_buf;
send_len = send(s_server, send_buf, 100, 0);
if (send_len < 0)
{
std::cout << "发送失败!" << std::endl;
break;
}
if (strcmp(send_buf, "bye") == 0)
{ //输入bye就断开通信
std::cout << "本次通信结束!" << std::endl;
break;
}
recv_len = recv(s_server, recv_buf, 100, 0);
if (recv_len < 0)
{
std::cout << "接受失败!" << std::endl;
break;
}
else
{
std::cout << "服务器端信息:" << recv_buf << std::endl;
}
}
5.关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())
closesocket(s_server);
WSACleanup();
至此,服务端与客户端完成通信,运行的时候键盘输入数据即可,记得先运行server端。