服务端与客户端通信
服务端:
1.打开网络库
int WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
2.检验版本号
2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion)? (检验版本号是 2.2)
3.创建socket 套接字
SOCKET socket(int af, int type, int protocol);
4.绑定地址与端口号
int bind(SOCKET s, const sockaddr* addr, int namelen);
5.进行监听
int WSAAPI listen(SOCKET s, int backlog);
6.接受链接(本质:创建客户端socket)
SOCKET WSAAPI accept(SOCKET s, sockaddr* addr, int *addrlen);
7.与客户端进行收发信息
收:int recv(SOCKET s, char *buf, int len, int flags);
发:int WSAAPI send(SOCKET s, const char *buf, int len, int flags);
客户端
1.打开网络库
int WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
2.检验版本号
2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion)? (检验版本号是 2.2)
3.创建socket 套接字(注:创建的socket是服务端的socket)
SOCKET socket(int af, int type, int protocol);
4.链接服务端
int WSAAPI connect(SOCKET s, const sockaddr *name, int namelen);
5.与服务端发收信息
发:int WSAAPI send(SOCKET s, const char *buf, int len, int flags);
收:int recv(SOCKET s, char *buf, int len, int flags);
代码:
服务端:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Winsock.h>
#pragma comment(lib,"ws2_32.lib")
// 定义 WSAStartup 参数2所需的结构体
WSADATA WSAData;
// 定义全局的socket
SOCKET socket_c;
// 1.打开网络库
void Open_WSAStartup()
{
// 1,打开网络库
WORD version = MAKEWORD(2, 2); //设置要使用的库的版本 MAKEWORD(主版本,副版本);
int n = WSAStartup(version, &WSAData);
// 检验是否成功打开网络库
if (0 != n)
{
// 打开网络库失败,通过n 返回的错误码,给出提示
switch (n)
{
case WSASYSNOTREADY:
printf("重启电脑试试,或者检查ws_2_32库是否存在\n");
break;
case WSAVERNOTSUPPORTED:
printf("当前库版本号不支持,尝试更换版本试试\n");
break;
case WSAEPROCLIM:
printf("已达到对Windows套接字实现支持的任务数量的限制\n");
break;
case WSAEINPROGRESS:
printf("正在阻止Windows Sockets 1.1操作,当前函数运行期间,因为某些原因造成阻塞\n");
break;
case WSAEFAULT:
printf("lpWASData参数不是有效的指针,参数写错了\n");
break;
default:
break;
}
}
}
// 2.校验版本
void CheckVersion()
{
// 2.校验版本
if (2 != HIBYTE(WSAData.wVersion) || 2 != LOBYTE(WSAData.wVersion))
{
// 打开版本号 2.2 失败
printf("打开版本号 2.2 失败, 正在退出程序...\n");
// 关闭网络库
WSACleanup();
// 退出程序
return;
}
}
// 3.创建套接字 socket
SOCKET CreateSocket(SOCKET createSocket)
{
// 3.创建套接字 socket
createSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 检验是否成功创建套接字
if (INVALID_SOCKET == createSocket)
{
// 创建套接字失败
// 获取错误码
int error = WSAGetLastError();
printf("创建套接字失败,返回错误号为:%d\n", error);
// 关闭网络库
WSACleanup();
// 退出程序
return 0;
}
return createSocket;
}
// 4.绑定地址与端口号
void Bind(SOCKET socketServer)
{
// 4.绑定地址与端口号
// 创建bind() 函数所需的第二个参数的结构体,该结构体装 地址类型,IP地址,端口号
sockaddr_in server_s;
server_s.sin_family = AF_INET; // 地址类型
server_s.sin_port = htons(12345); // 端口号
server_s.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // ip地址
int isbind = bind(socketServer, (struct sockaddr*)&server_s, sizeof(server_s));
// 检验绑定地址与端口号是否成功
if (SOCKET_ERROR == isbind)
{
// 绑定地址与端口号失败
// 获取错误号
int error = WSAGetLastError();
printf("绑定端口号和IP地址失败,返回错误号为:%d\n", error);
// 关闭套接字
closesocket(socketServer);
// 关闭网络库
WSACleanup();
// 退出程序
return;
}
}
// 5.进行监听
void Listen(SOCKET socketServer)
{
// 5.进行监听
if (SOCKET_ERROR == listen(socketServer, SOMAXCONN))
{
// 套接字中断了侦听传入连接的状态
// 获取错误号
int error = WSAGetLastError();
printf("监听失败,返回错误号为:%d\n", error);
// 关闭套接字
closesocket(socketServer);
// 关闭网络库
WSACleanup();
// 退出程序
return;
}
}
// 6.进行链接 创建客户端socket
SOCKET Accpet(SOCKET socketServer)
{
// 6.创建客户端socket,接受连接
//SOCKET socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 创建accpet() 函数参数二所需的结构体体,用来装ip 和端口号
sockaddr_in client_s;
//给结构体成员赋值
client_s.sin_family = AF_INET; //地址类型
client_s.sin_port = htons(12345); //端口号
client_s.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //ip地址
// 获取结构体的大小
int len = sizeof(client_s);
SOCKET c_socketClient = accept(socketServer, (sockaddr*)&client_s, &len);
// 检验是否设置接收连接状态
if (INVALID_SOCKET == c_socketClient)
{
// 退出了接受链接状态
// 获取错误号
int error = WSAGetLastError();
printf("连接失败,返回错误号为:%d\n", error);
// 关闭套接字
closesocket(socketServer);
// 关闭客户端套接字
closesocket(c_socketClient);
// 关闭网络库
WSACleanup();
// 退出程序
return 0;
}
return c_socketClient;
}
int main()
{
// 1.打开网络库
Open_WSAStartup();
// 2.校验版本
CheckVersion();
// 3.创建套接字 socket
SOCKET socketServer = CreateSocket(socket_c);
// 4.绑定地址与端口号
Bind(socketServer);
// 5.进行监听
Listen(socketServer);
// 6.创建客户端socket,接受连接
SOCKET socketClient = Accpet(socketServer);
// 与客户端进行收发信息
// 收信息
// 定义字节数组,用来接收客户端发来的信息的缓存区
/*char recvBuf[1024] = { 0 };
recv(socketClient, recvBuf, 1024, 0);
printf("%s\n", recvBuf);*/
printf("成功连接,我是服务端,请客户端发送信息...\n");
while (1)
{
//收信息
char recvBuf[1024] = { 0 };
int ret = recv(socketClient, recvBuf, 1024, 0);
// 判断recv 返回值
if (ret == SOCKET_ERROR)
{
// 打印错误码
printf("recv failed :%d\n", WSAGetLastError());
// 退出程序
break;
}
else if (ret == 0)
{
// 客户端下线了
printf("Connection closed\n");
break;
}
else
{
printf("客户端say : %s\n", recvBuf);
}
// 发信息
// 定义发送字节的数组
char sendBuf[1024] = { 0 };
scanf_s("%s", sendBuf, 1024);
send(socketClient, sendBuf, 1024, 0);
}
// 注意用完之后要关闭网络库和套接字
// 关闭套接字
closesocket(socketServer);
// 关闭客户端套接字
closesocket(socketClient);
// 关闭网络库
WSACleanup();
system("pause");
return 0;
}
客户端:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Winsock.h>
#pragma comment(lib,"ws2_32.lib")
WSADATA WSAData;
// 1,打开网络库
void OpenWSAStarup()
{
// 1,打开网络库
WORD version = MAKEWORD(2, 2); //设置要使用的库的版本 MAKEWORD(主版本,副版本);
int n = WSAStartup(version, &WSAData);
// 检验是否成功打开网络库
if (0 != n)
{
// 打开网络库失败,通过n 返回的错误码,给出提示
switch (n)
{
case WSASYSNOTREADY:
printf("重启电脑试试,或者检查ws_2_32库是否存在\n");
break;
case WSAVERNOTSUPPORTED:
printf("当前库版本号不支持,尝试更换版本试试\n");
break;
case WSAEPROCLIM:
printf("已达到对Windows套接字实现支持的任务数量的限制\n");
break;
case WSAEINPROGRESS:
printf("正在阻止Windows Sockets 1.1操作,当前函数运行期间,因为某些原因造成阻塞\n");
break;
case WSAEFAULT:
printf("lpWASData参数不是有效的指针,参数写错了\n");
break;
}
}
}
// 2.检验版本
void CheckVersion()
{
if (2 != HIBYTE(WSAData.wVersion) || 2 != LOBYTE(WSAData.wVersion))
{
// 打开版本号 2.2 失败
printf("打开版本号 2.2 失败, 正在退出程序...\n");
// 关闭网络库
WSACleanup();
// 退出程序
return;
}
}
// 3.创建socket
SOCKET CreateSocket()
{
// 3.创建套接字 socket 创建服务端的socket
SOCKET socketCreate = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// 检验是否成功创建套接字
if (INVALID_SOCKET == socketCreate)
{
// 创建套接字失败
// 获取错误码
int error = WSAGetLastError();
printf("创建套接字失败,返回错误号为:%d\n", error);
// 关闭网络库
WSACleanup();
// 退出程序
return 0;
}
return socketCreate;
}
// 4.连接服务器
void Connection(SOCKET socket_)
{
// 4.连接到服务器
// 创建connect() 函数中参数2所需的结构体 用来装IP地址和端口号
sockaddr_in client_s;
//给结构体成员赋值
client_s.sin_family = AF_INET; //IP地址类型
client_s.sin_port = htons(12345); //端口号
client_s.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int nCon = connect(socket_, (struct sockaddr*)&client_s, sizeof(client_s));
// 检验是否成功连接到服务端
if (SOCKET_ERROR == nCon)
{
// 连接服务端失败
// 获取错误码
int error = WSAGetLastError();
printf("连接服务端失败,返回错误号为:%d\n", error);
// 关闭套接字
closesocket(socket_);
// 关闭网络库
WSACleanup();
// 退出程序
return;
}
}
int main()
{
// 1,打开网络库
OpenWSAStarup();
// 2.校验版本
CheckVersion();
// 3.创建socket
SOCKET socketServer = CreateSocket();
// 4.连接服务器
Connection(socketServer);
printf("我是客户端,正在发送信息,请稍等...\n");
//send(socketServer, "来自客户端的信息...", sizeof("来自客户端的信息..."), 0);
// 5.与服务端进行收发信息
while (1)
{
// 发信息
char sendBuf[1024] = { 0 };
scanf_s("%s", sendBuf, 1024);
send(socketServer, sendBuf, 1024, 0);
// 收信息
// 定义接收服务端信息的缓存区
char recvBuf[1024] = { 0 };
int res = recv(socketServer, recvBuf, 1024, 0);
// 判断是否成功接收到信息
if (0 == res)
{
printf("服务端下线了\n");
break;
}
else if (SOCKET_ERROR == res)
{
// 获取错误码
int error = WSAGetLastError();
printf("连接服务端失败,返回错误号为:%d", error);
printf("\n");
break;
}
else
{
// 打印信息
printf("服务端say: %s\n", recvBuf);
}
}
// 关闭套接字
closesocket(socketServer);
// 关闭网络库
WSACleanup();
system("pause");
return 0;
}
程序运行结果:
?注:必须先打开服务端,如果是先启动的客户端会出现一下错误:
?
?
|