简单c/s模型

函数说明
- 打开网络库
一切网络函数操作都需要先打开windows的网络库
网络库需要使用#include <WinSock2.h>库
打开网络库的函数WSAStartup(WORD version, LPWSADATA lpWSAData);
version: 定义使用那个版本的网络函数 MAKEAORD(主版本号,副版本号)
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
int main(void)
{
WORD version = MAKEWORD(2,2);
WSADATA wsaData;
WSAStartup(version, &wsaData);
}
- socket
socket封装了底层的复杂协议 在代码里面通过socket就可以完成网络通信 不需要考虑传输层 网络层 链路层和网络驱动这些操作
创建socket函数socket(地址类型,socket类型,协议类型)
地址类型:
| 宏定义 | 含义 |
|---|
| AF_INET | IP地址是ipv4 |
| AF_INET6 | IP地址是ipv6 |
| AF_BTH | 蓝牙 |
| AF_IRDA | 红外 |
socket类型
| 宏定义 | 含义 |
|---|
| SOCK_STREAM | 使用TCP传输 |
| SOCK_DGRAM | 使用UDP传输 |
| SOCK_RDM | 局域网内多播 |
| SOCK_RAW | 原始套接字 |
协议类型
| 宏定义 | 含义 |
|---|
| IPPROTO_TCP | TCP协议 |
| IPPROTO_UDP | UDP协议 |
| IPPROTO_ICMP | ICMP协议 |
int main(void)
{
SOCKET socket = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == socket)
{
int errno = WSAGetLastError();
printf("创建socket失败 错误码:%d", errno);
}
else
{
printf("创建socket成功");
}
}
SOCKADDR_IN bindMsg
bindMsg.sin_family = AF_INET
bindMsg.sin_port = 22333
inet_pton(AF_INET, "127.0.0.1", (void*)(&bindMsg.sin_addr.s_addr))
if(SOCKET_ERROR == bind(socket, (SOCKADDR*)(&bindMsg), sizeof(SOCKADDR)))
{
int errno = WSAGetLastError()
printf("bind函数执行失败 错误码:%d", errno)
}
- listen
只有调用这个函数 客户端才能通过网络访问服务器 服务器开始监听外部对服务器的请求
服务器的请求有上限 当超过请求上限后 在对服务器的请求会进入到队列中 这个队列就是挂起队列
当挂起队列也满了 就会拒绝客户端的访问
listen(服务器监听客户端连接的socket, 挂起队列长度)
SOMAXCONN让系统决定挂起队列长度
if(SOCKET_ERROR == listen(socket, SOMAXCONN))
{
int errno = WSAGetLastError()
printf("listen函数执行失败 错误码:%d", errno)
}
- accept
根据listen监听到的客户端信息 创建一个与客户端通信的socket
SOCKADDR_IN clientMsg
int clientMsgLen = sizeof(SOCKADDR_IN)
SOCKET clientSocket = accept(serverSocket, (SOCKADDR*)(&clientMsg), &clientMsgLen)
if(INVALID_SOCKET == clientSocket)
{
int errno = WSAGetLastError()
printf("accept执行失败 错误码:%d", errno)
}
SOCKADDR_IN serverMsg
serverMsg.sin_family = AF_INET
serverMsg.sin_port = 22333
inet_pton(AF_INET, "127.0.0.1", (void*)(&serverMsg.sin_addr.s_addr))
connect(serverSocket, (SOCKADDR*)(&serverMsg), sizeof())
- recv
客户端和服务端通信客户端数据是放到协议缓冲区的 recv的本质是将协议缓冲区的数据放到应用缓冲区里
clientsocket: accept函数创建的与客户端通信的socket
buf: 代码中缓冲区
len: 重协议缓冲区复制到代码缓冲区的长度
参数0的作用: 每一次从协议缓冲区复制到代码中的缓冲区就将协议缓冲区里面len长度的字符删掉 否则会重复读取
char buf[1024] = {0};
recv(clientSocket, buf, sizeof(buf), 0)
- send
将代码中缓冲区的数据复制到协议缓冲区中 什么时候发送由系统决定
char sendbuf[1024] = {0};
strcpy(sendbuf, 1024, "欢迎访问服务器");
send(clientSocket, sendbuf, sizeof(sendbuf), 0);
closesocket(socket);
WSACleanup();
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
int main(void)
{
WORD version = MAKEWORD(2, 2);
WSADATA netMsg;
int isStart = WSAStartup(version, &netMsg);
int errno;
int sendCount;
int recvCount;
if (isStart != 0)
{
errno = WSAGetLastError();
printf("|# 服务端网络库打开失败. 错误码: %d\n", errno);
return 0;
}
printf("|# 服务端网络库打开成功.\n");
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == serverSocket)
{
errno = WSAGetLastError();
printf("|# 服务端socket创建失败. 错误码: %d\n", errno);
WSACleanup();
return 0;
}
SOCKADDR_IN bindMsg;
bindMsg.sin_family = AF_INET;
bindMsg.sin_port = 22333;
inet_pton(AF_INET, "127.0.0.1", (void*)(&bindMsg.sin_addr.s_addr));
if (SOCKET_ERROR == bind(serverSocket, (SOCKADDR*)(&bindMsg), sizeof(bindMsg)))
{
printf("|# bind执行失败\n");
closesocket(serverSocket);
WSACleanup();
return 0;
}
printf("|# bind执行成功. |# 协议类型:%s |# 端口号:%d |# IP地址: %s\n", "AF_INET", 22333, "127.0.0.1");
if (SOCKET_ERROR == listen(serverSocket, SOMAXCONN))
{
printf("|# listen执行失败. 无法监听端口 端口号:%d\n", 22333);
closesocket(serverSocket);
WSACleanup();
return 0;
}
printf("|# listen执行成功 |# 监听端口号:%d\n", 22333);
SOCKADDR_IN clientMsg;
int clientMsgLen = sizeof(SOCKADDR_IN);
SOCKET clientSocket = accept(serverSocket, (SOCKADDR*)(&clientMsg), &clientMsgLen);
if (INVALID_SOCKET == clientSocket)
{
errno = WSAGetLastError();
printf("|# 服务端创建与客户端通信的socket失败 错误码: %d\n", errno);
closesocket(serverSocket);
closesocket(clientSocket);
WSACleanup();
return 0;
}
printf("|# 服务端创建与客户端通信的socket成功. |# 客户端协议类型:%d |# 客户端端口:%d |# 客户端IP地址:%ld\n",
clientMsg.sin_family, clientMsg.sin_port, clientMsg.sin_addr.s_addr);
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
char* tmp = "~~欢迎访问服务器~~\n";
strcpy_s(sendbuf, 1024, tmp);
sendCount = send(clientSocket, sendbuf, sizeof(sendbuf), 0);
if (sendCount == SOCKET_ERROR)
{
errno = WSAGetLastError();
printf("|# 向客户端发送信息失败 错误码: %d |# 要发送的数据:%s |# 客户端协议类型:%d |# 客户端端口号:%d |# 客户端IP地址: %ld\n",
errno, sendbuf, clientMsg.sin_family, clientMsg.sin_port, clientMsg.sin_addr.s_addr);
closesocket(serverSocket);
closesocket(clientSocket);
WSACleanup();
return 0;
}
printf("|# 发送数据成功 数据:%s\n", sendbuf);
while (1)
{
recvCount = recv(clientSocket, recvbuf, sizeof(recvbuf), 0);
if (0 == recvCount)
{
printf("|# 客户端下线\n");
closesocket(serverSocket);
closesocket(clientSocket);
WSACleanup();
return 0;
}
else if (SOCKET_ERROR == recvCount)
{
errno = WSAGetLastError();
printf("|# 接收客户端数据失败. 错误码: %d\n", errno);
closesocket(serverSocket);
closesocket(clientSocket);
WSACleanup();
return 0;
}
else
{
printf("|# 客户端数据: %s\n", recvbuf);
}
if (strcmp("EXIT", recvbuf) == 0)
{
break;
}
strcpy_s(sendbuf, 1024, recvbuf);
send(clientSocket, sendbuf, sizeof(sendbuf), 0);
}
printf("|# 客户端退出.\n");
closesocket(serverSocket);
closesocket(clientSocket);
WSACleanup();
return 0;
}
int main(void)
{
WORD version = MAKEWORD(2, 2)
WSADATA netMsg
int isStart = WSAStartup(version, &netMsg)
int errno
int sendCount
int recvCount
if (isStart != 0)
{
errno = WSAGetLastError()
printf("|
return 0
}
printf("|
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
if (INVALID_SOCKET == serverSocket)
{
errno = WSAGetLastError()
printf("|
WSACleanup()
return 0
}
SOCKADDR_IN serverMsg
serverMsg.sin_family = AF_INET
serverMsg.sin_port = 22333
inet_pton(AF_INET, "127.0.0.1", (void*)(&serverMsg.sin_addr.s_addr))
if (SOCKET_ERROR == connect(serverSocket, (SOCKADDR*)(&serverMsg), sizeof(serverMsg)))
{
printf("|
closesocket(serverSocket)
WSACleanup()
return 0
}
char sendbuf[1024] = {0}
char recvbuf[1024] = {0}
recvCount = recv(serverSocket, recvbuf, sizeof(recvbuf), 0)
if (SOCKET_ERROR == recvCount)
{
printf("|
closesocket(serverSocket)
WSACleanup()
return 0
}
else
{
printf("|
}
while (1)
{
// scanf_s("%s", sendbuf, 1024)
// scanf_s会对空格截断 改为gets_s
gets_s(sendbuf, 1024)
sendCount = send(serverSocket, sendbuf, sizeof(sendbuf), 0)
if (strcmp("EXIT", sendbuf) == 0)
{
break
}
if (sendCount == SOCKET_ERROR)
{
errno = WSAGetLastError()
printf("|
closesocket(serverSocket)
WSACleanup()
return 0
}
recvCount = recv(serverSocket, recvbuf, sizeof(recvbuf), 0)
if (recvCount == SOCKET_ERROR)
{
errno = WSAGetLastError()
printf("|
closesocket(serverSocket)
WSACleanup()
return 0
}
printf("|
}
printf("|
closesocket(serverSocket)
WSACleanup()
return 0
}
结果
