2020-11-04
程序员文章站
2022-04-08 21:39:10
...
如何让服务器端持续不断地监听客户端的请求?
sever服务器端:
#include <stdio.h>
#include <WinSock2.h>
#pragma comment (lib,"ws2_32.lib")//把ws2_32.lib 这个库加入到工程文件中
#include <Ws2tcpip.h>//为了使用 inet_pton(PF_INET, "127.0.0.1", &sockAddr.sin_addr.s_addr);
//2019版本的VS不支持直接使用inet_addr("127.0.0.1");
#define BUF_SIZE 100
int main() {
//初始化DLL
WSADATA wsaData;//WSADATA,一种结构体,这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据。它包含Winsock.dll执行的数据。
WSAStartup(MAKEWORD(2, 2), &wsaData);//MAKEWORD(2, 2):WinSock的版本号为2.2; 将WinSock版本号写入wsaData结构体中
//创建套接字
SOCKET severSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);//第一个参数表示IP地址类型,PF_INET 表示 IPv4 地址,例如 127.0.0.1;
//第二个参数表示数据传输方式/套接字类型,SOCK_STREAM(流格式套接字/面向连接的套接字)
//第三个参数表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示TCP传输协议和UDP传输协议
//绑定套接字
sockaddr_in sockAddr;//sockaddr_in为固定的结构体,详见socket编程11 http://c.biancheng.net/view/2345.html
memset(&sockAddr, 0, sizeof(sockAddr));//每个字节都用0填充 先将sockaddr_in中的16个字节都填充成0
sockAddr.sin_family = PF_INET;//使用IPv4地址,sin_family为地址类型,IPv4还是IPv6,2个字节
//sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");//sin_addr表示具体的IP地址,4个字节,是in_addr类型的结构体,该结构只包含一个成员s_addr
//s_sddr的类型为in_addr_t,等价于unsigned long,是一个整数,但IP地址是一个字符串所以需要 inet_addr() 函数进行转换
inet_pton(PF_INET, "127.0.0.1", &sockAddr.sin_addr.s_addr);
sockAddr.sin_port = htons(1234);//端口,2个字节
bind(severSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));//服务器端要用bind()函数将套接字与特定的IP地址和端口绑定起来
//只有这样,流经该 IP 地址和端口的数据才能交给套接字处理
//类似地,客户端也要用connect()函数建立连接
//(SOCKADDR*)&sockAddr表示将sockaddr_in类型强制转换为SOCKADDR
//进入监听状态
listen(severSock, 20);//listen() 函数可以让套接字进入被动监听状态 int listen(SOCKET sock, int backlog); backlog 为请求队列的最大长度
//所谓被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。
//当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。这个缓冲区,就称为请求队列
//缓冲区的长度(能存放多少个客户端请求)可以通过 listen() 函数的 backlog 参数指定,但究竟为多少并没有什么标准
//接收客户端请求
SOCKADDR clntAddr;
int nSize = sizeof(SOCKADDR);
//sock 为服务器端套接字,addr 保存了客户端的IP地址和端口号 sock(服务器套接字,旧的)->addr(新的套接字)
char buffer[BUF_SIZE] = { 0 };//缓冲区
while (1) {
SOCKET clntSock = accept(severSock, (SOCKADDR*)&clntAddr, &nSize);//SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);
int strLen = recv(clntSock, buffer, BUF_SIZE, 0);//接收客户端发来的数据
//int recv(SOCKET sock, char *buf, int len, int flags);
send(clntSock, buffer, BUF_SIZE, 0);//将数据原样返回
closesocket(clntSock); //关闭套接字
memset(buffer, 0, BUF_SIZE); //重置缓冲区
}
//关闭套接字
closesocket(severSock);
//终止DLL的使用
WSACleanup();
return 0;
}
client客户接收端:
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib") //加载 ws2_32.dll
#include <Ws2tcpip.h>
#pragma warning(disable:4996) //避免出现scanf的警告
#define BUF_SIZE 100
int main() {
//初始化DLL
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//创建套接字
//向服务器发起请求
sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = PF_INET;
//sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
inet_pton(PF_INET, "127.0.0.1", &sockAddr.sin_addr.s_addr);
sockAddr.sin_port = htons(1234);
char bufSend[BUF_SIZE] = { 0 };
char bufRecv[BUF_SIZE] = { 0 };
while (1) {
//创建套接字
SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
//获取用户输入的字符串并发送给服务器
printf("请输入内容:");
gets_s(bufSend);
send(sock, bufSend, strlen(bufSend), 0);
//接收服务器传回的数据
recv(sock, bufRecv, BUF_SIZE, 0);
//输出接收到的数据
printf("返回内容:%s\n", bufRecv);
memset(bufSend, 0, BUF_SIZE); //重置缓冲区
memset(bufRecv, 0, BUF_SIZE); //重置缓冲区
//关闭套接字
closesocket(sock);
}
//终止使用DLL
WSACleanup();
return 0;
}
上一篇: List、Set、Map集合
下一篇: EasyTcpServer建立
推荐阅读