使用 WinSock 处理多个用户
Handling multiple users using WinSock
我正在关注 this tutorial,它展示了如何在不使用多线程的情况下接受多个连接。
我 运行 遇到的问题是 accept()
函数总是 return SOCKET_ERROR
.
我希望服务器接受多个客户端。我希望有人能指出我做错了什么。
这是我的服务器代码:
#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <stdio.h>
#include <signal.h>
#include <conio.h>
#include <assert.h>
#include <Windows.h>
#include <iostream>
//sockets
#define CLIENT_CON 10
#define CLIENT_DIS 20
#define BF_SZ 100
#define MAX_CONS 5
SOCKET sock, clien;
int PR_CONS = 0;
struct _client
{
bool con; // Set true if a client is connected
sockaddr_in addr; // Client info like ip address
SOCKET cs; // Client socket
fd_set set; // used to check if there is data in the socket
int i; // any piece of additional info
};
_client client[10];
int accept(_client*);
int send(_client*, char*,int);
int recv(_client*, char*, int);
void Server_Status(int );
void char_message(char*);
void accept_clients();
void recv_client();
int main() {
//int res;
int i = 1;
int port = 5150;
SOCKET sock;
WSADATA ws;
printf("\t Echo Server (Multiple client support)\n");
sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_addr.S_un.S_addr = INADDR_ANY;
ser.sin_port = htons(port);
WSAStartup(MAKEWORD(2,2),&ws);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i,sizeof(i));
bind(sock,(SOCKADDR*)&ser, sizeof(ser));
listen(sock,5);
printf("listening \n");
unsigned long b= 1;
ioctlsocket(sock,FIONBIO,&b);
for(int i = 0; i < MAX_CONS; i++) {
client[i].con = false;
}
while(true) {
accept_clients();
recv_client();
}
}
int accept(_client* x) {
x->i = sizeof(sockaddr_in);
x->cs = accept(sock, (SOCKADDR*)&x->addr, &x->i);
if(x->cs != INVALID_SOCKET ) {
std::cout << x->cs << std::endl;
x->con = true;
FD_ZERO(&x->set);
FD_SET(x->cs,&x->set);
printf("accepted client");
return true;
}
//printf("failed to accept client");
return false;
}
int send(_client* x, char* buffer, int sz) {
x->i = send(x->cs, buffer, sz, 0);
if(x-> i == SOCKET_ERROR || x->i == 0 ) {
return false;
}
return true;
}
int recv(_client *x, char* buffer, int sz) {
if(FD_ISSET(x->cs,&x->set)) {
x->i = recv(x->cs,buffer,sz, 0);
if(x->i == 0) {
return false;
}
return true;
}
return false;
}
void accept_clients() {
for(int i = 0; i < MAX_CONS; i++) {
if(!client[i].con) {
if(accept(&client[i])) {
Server_Status(CLIENT_CON);
}
}
}
}
void Server_Status(int msg) {
if(msg == CLIENT_CON) {
PR_CONS++;
printf("client has connected");
}
else if(msg == CLIENT_DIS) {
PR_CONS--;
printf("client has disconnected");
}
else {
printf("we got unknown message");
}
}
void chat_message(char* s) {
int len = strlen(s);
for(int i = 0; i< MAX_CONS; i++) {
if(client[i].con) {
send(&client[i], s, len);
}
}
}
void recv_client() {
char buffer[BF_SZ];
for(int i = 0; i < MAX_CONS; i++) {
if(client[i].con) {
if(recv(&client[i],buffer, BF_SZ)) {
if(buffer[0] == '/') {
if(strcmp(buffer, "/server_bang") == 0) {
chat_message("** Hi**");
}
}
else {
chat_message(buffer);
}
}
}
}
}
The problem I run into is that the accept()
function always return SOCKET_ERROR
.
那是因为您向它传递了一个无效的 SOCKET
句柄(如果您在收到 SOCKET_ERROR
后不厌其烦地检查 WSAGetLastError()
,它可能会返回 WSAENOTSOCK
).
原因是因为您的 accept()
包装函数正在调用 Winsock 的 accept()
函数,其中包含一个名为 sock
的 全局 SOCKET
变量 ],但是您的 main()
函数永远不会初始化该变量!它正在初始化一个 local SOCKET
变量 ,它也被命名为 sock
。您需要:
摆脱 main()
的本地 sock
变量,这样 main()
将使用全局 sock
变量。
摆脱全局 sock
变量,并让 main()
将其局部 sock
变量作为输入参数传递给 accept_clients()
函数,然后可以将其作为输入参数传递给 accept()
函数。
我正在关注 this tutorial,它展示了如何在不使用多线程的情况下接受多个连接。
我 运行 遇到的问题是 accept()
函数总是 return SOCKET_ERROR
.
我希望服务器接受多个客户端。我希望有人能指出我做错了什么。
这是我的服务器代码:
#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <stdio.h>
#include <signal.h>
#include <conio.h>
#include <assert.h>
#include <Windows.h>
#include <iostream>
//sockets
#define CLIENT_CON 10
#define CLIENT_DIS 20
#define BF_SZ 100
#define MAX_CONS 5
SOCKET sock, clien;
int PR_CONS = 0;
struct _client
{
bool con; // Set true if a client is connected
sockaddr_in addr; // Client info like ip address
SOCKET cs; // Client socket
fd_set set; // used to check if there is data in the socket
int i; // any piece of additional info
};
_client client[10];
int accept(_client*);
int send(_client*, char*,int);
int recv(_client*, char*, int);
void Server_Status(int );
void char_message(char*);
void accept_clients();
void recv_client();
int main() {
//int res;
int i = 1;
int port = 5150;
SOCKET sock;
WSADATA ws;
printf("\t Echo Server (Multiple client support)\n");
sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_addr.S_un.S_addr = INADDR_ANY;
ser.sin_port = htons(port);
WSAStartup(MAKEWORD(2,2),&ws);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&i,sizeof(i));
bind(sock,(SOCKADDR*)&ser, sizeof(ser));
listen(sock,5);
printf("listening \n");
unsigned long b= 1;
ioctlsocket(sock,FIONBIO,&b);
for(int i = 0; i < MAX_CONS; i++) {
client[i].con = false;
}
while(true) {
accept_clients();
recv_client();
}
}
int accept(_client* x) {
x->i = sizeof(sockaddr_in);
x->cs = accept(sock, (SOCKADDR*)&x->addr, &x->i);
if(x->cs != INVALID_SOCKET ) {
std::cout << x->cs << std::endl;
x->con = true;
FD_ZERO(&x->set);
FD_SET(x->cs,&x->set);
printf("accepted client");
return true;
}
//printf("failed to accept client");
return false;
}
int send(_client* x, char* buffer, int sz) {
x->i = send(x->cs, buffer, sz, 0);
if(x-> i == SOCKET_ERROR || x->i == 0 ) {
return false;
}
return true;
}
int recv(_client *x, char* buffer, int sz) {
if(FD_ISSET(x->cs,&x->set)) {
x->i = recv(x->cs,buffer,sz, 0);
if(x->i == 0) {
return false;
}
return true;
}
return false;
}
void accept_clients() {
for(int i = 0; i < MAX_CONS; i++) {
if(!client[i].con) {
if(accept(&client[i])) {
Server_Status(CLIENT_CON);
}
}
}
}
void Server_Status(int msg) {
if(msg == CLIENT_CON) {
PR_CONS++;
printf("client has connected");
}
else if(msg == CLIENT_DIS) {
PR_CONS--;
printf("client has disconnected");
}
else {
printf("we got unknown message");
}
}
void chat_message(char* s) {
int len = strlen(s);
for(int i = 0; i< MAX_CONS; i++) {
if(client[i].con) {
send(&client[i], s, len);
}
}
}
void recv_client() {
char buffer[BF_SZ];
for(int i = 0; i < MAX_CONS; i++) {
if(client[i].con) {
if(recv(&client[i],buffer, BF_SZ)) {
if(buffer[0] == '/') {
if(strcmp(buffer, "/server_bang") == 0) {
chat_message("** Hi**");
}
}
else {
chat_message(buffer);
}
}
}
}
}
The problem I run into is that the
accept()
function always returnSOCKET_ERROR
.
那是因为您向它传递了一个无效的 SOCKET
句柄(如果您在收到 SOCKET_ERROR
后不厌其烦地检查 WSAGetLastError()
,它可能会返回 WSAENOTSOCK
).
原因是因为您的 accept()
包装函数正在调用 Winsock 的 accept()
函数,其中包含一个名为 sock
的 全局 SOCKET
变量 ],但是您的 main()
函数永远不会初始化该变量!它正在初始化一个 local SOCKET
变量 ,它也被命名为 sock
。您需要:
摆脱
main()
的本地sock
变量,这样main()
将使用全局sock
变量。摆脱全局
sock
变量,并让main()
将其局部sock
变量作为输入参数传递给accept_clients()
函数,然后可以将其作为输入参数传递给accept()
函数。