拒绝连接到服务器C套接字编程
我有一个小问题:我的服务器明白他不能接受新的连接,但客户端仍认为他已连接。 我不知道如何解决这个问题。拒绝连接到服务器C套接字编程
我的客户端代码:
#include<stdio.h> //printf
#include<string.h> //strlen
#include<sys/socket.h> //socket
#include<arpa/inet.h> //inet_addr
#include <fcntl.h> // for open
#include <unistd.h> // for close
int main(int argc , char *argv[]){
int sock;
struct sockaddr_in server;
char message[1000] , server_reply[2000];
//Create socket
sock = socket(AF_INET , SOCK_STREAM , 0);
if (sock == -1){
printf("Could not create socket");
}
puts("Socket created");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(8080);
//Connect to remote server
if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0){
perror("connect failed. Error");
return 1;
}
puts("Connected\n");
//keep communicating with server
while(1){
printf("Enter message : ");
scanf("%s" , message);
//Send some data
if(send(sock , message , strlen(message) , 0) < 0){
puts("Send failed");
return 1;
}
//Receive a reply from the server
if(recv(sock , server_reply , 2000 , 0) < 0){
puts("recv failed");
break;
}
puts("Server reply :");
puts(server_reply);
}
close(sock);
return 0;
}
而我的服务器代码:
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading , link with lpthread
#define MAX_PLAYER 4
void *connection_handler(void *);
int nbrePlayer = 0;
int main(int argc , char *argv[]){
int socket_desc , client_sock , c , *new_sock;
struct sockaddr_in server , client;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8080);
//Bind
if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0){
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
if(listen(socket_desc , 4)<0){
perror("listen");
return 1;
}
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))>0){
if(nbrePlayer>=MAX_PLAYER){
puts("connection refused");
close(client_sock);
continue;
} else {
puts("Connection accepted");
}
nbrePlayer++;
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = client_sock;
if(pthread_create(&sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0){
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
//pthread_join(sniffer_thread , NULL);
puts("Handler assigned");
printf("%d\n",nbrePlayer);
}
if (client_sock < 0){
perror("accept failed");
return 1;
}
return 0;
}
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc){
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
//Receive a message from client
while((read_size = recv(sock , client_message , 2000 , 0)) > 0){
//Send the message back to client
write(sock , client_message , strlen(client_message));
}
if(read_size == 0){
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1){
perror("recv failed");
}
//Free the socket pointer
free(socket_desc);
`nbrePlayer`--;
//Delete the player for the shared memory
return 0;
}
THX着您的答案
这是因为在这里你正在检查,如果连接最初正确启动,如果超过了一定数量的球员,则不是。
为了达到您喜欢的程度,您可能希望创建与您的程序可用的数据有关的特殊消息。
例如:连接时,如果超过了播放器的数量,服务器会向客户端发送一条消息,告诉他他的请求被拒绝,然后关闭套接字服务器端。收到此消息后,客户端在关闭自己的套接字之前会向用户显示一个很好的错误。
这样你就可以在两端都有适当的连接拒绝和套接字关闭。
你的回应对于一个务实的程序员来说是好的,但是如何让服务器拒绝连接(不接受他们说某事并断开客户端)呢?问题不是关于游戏,而是关于socket API的工作原理。 –
在您的应用程序中,服务器首先接受连接,然后关闭它,当它满足一定条件时,客户端在套接字发送连接到服务器时,套接字发送并不总是检测到关闭/断开的连接,但recv总是检测它。 因此,您应该考虑设计应用程序,以便客户端在连接后首先执行recv(期待欢迎消息),以便从服务器检测到关闭的套接字。
另一种方式可能是,如果条件nbrePlayer == MAX_PLAYER-1符合,您不应该调用accept,以便在客户端的connect()获取错误 为此,您需要将1作为backlog参数传递给listen()所以没有进入插座放在队列由听(),等待获得通过接受()调用 但积压的行为是受对底层平台按本实施后接受 listen() ignores the backlog argument?
刚落听值为listen(sock_fd, 0);
将禁止任何传入连接,而服务器不在accept(2)
系统调用。客户端将收到来自connect(2)
系统调用的ECONNREF
(“拒绝连接”)。
注:
刚才试了,它不工作... Linux内核默默地忽略0
值(或指使用默认,只需要检查)
另一种可能是关闭接受套接字描述符,在这种情况下,您可能会失去对下一个连接中同一端口的访问,但它并未被使用,因此内核如何知道您要保留。附加的是一个简单的回声服务器,它实现了接受描述符的关闭,它的工作原理!(我已经包含的代码来获得分配的端口的连接内核,如果你不这样做bind(2)
系统调用,因此它的同一端口下一次)
/* $Id: srv.c,v 1.6 2012/01/21 18:14:31 luis Exp $
* Author: Luis Colorado <[email protected]>
* Date: Thu Feb 26 12:44:15 MET 1998
*/
#define PROGNAME "srv"
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <netdb.h>
extern char *optarg;
extern int optind, opterr, optopt;
int bind_port = 0;
int listen_val = 0;
int main (int argc, char **argv)
{
int opt, sd, res;
/* process the program options... */
while ((opt = getopt(argc, argv, "b:l:")) != EOF) {
switch (opt) {
case 'b': bind_port = atol(optarg); break;
case 'l': listen_val = atol(optarg); break;
} /* switch */
} /* while */
/* Construct the sockaddr_in for the connect system call */
for(;;) {
sd = socket (AF_INET, SOCK_STREAM, 0);
if (sd < 0) {
perror (PROGNAME ": socket");
} /* if */
if (bind_port) {
struct sockaddr_in srv_name;
srv_name.sin_family = AF_INET;
srv_name.sin_port = htons(bind_port);
srv_name.sin_addr.s_addr = INADDR_ANY;
int res = bind(sd,
(const struct sockaddr *)&srv_name,
sizeof srv_name);
if (res < 0) {
perror(PROGNAME ": bind");
exit(1);
}
printf(PROGNAME ": bound to port %d\n", bind_port);
}
if (listen_val >= 0) {
int res = listen(sd, listen_val);
if (res < 0) {
perror(PROGNAME ": listen");
exit(1);
}
printf(PROGNAME ": listen set to %d\n", listen_val);
}
{
struct sockaddr_in server;
int server_sz = sizeof server;
int res = getsockname(sd,
(struct sockaddr *) &server,
&server_sz);
bind_port = ntohs(server.sin_port);
printf("bound to port %d\n", bind_port);
}
struct sockaddr_in client;
int client_sz = sizeof client;
int cd = accept(sd,
(struct sockaddr *)&client,
&client_sz);
if (cd == -1) {
perror (PROGNAME ": accept");
break;
} /* if */
/*************************************************
* THIS IS THE TRICK... JUST CLOSE THE ACCEPTING
* SOCKET AND THE SERVER WILL REFUSE INCOMING
* CONNECTIONS FROM THEN ON.
*************************************************/
close(sd);
printf("Accepted connection from %s:%d\n",
inet_ntoa(client.sin_addr),
ntohs(client.sin_port));
char *greeting = PROGNAME": This is the echo "
"server ready for input\r\n";
write(cd, greeting, strlen(greeting));
char buffer[1024];
ssize_t n;
while ((n = read(cd, buffer, sizeof buffer)) > 0) {
printf("Recibido: [%.*s]\n", n, buffer);
write(cd, buffer, n);
} /* while */
if(n < 0) {
perror(PROGNAME ": read");
} else { /* == 0 */
printf("Recibido: EOF\n");
char *greeting = "\r\n" PROGNAME ": Have a nice day :)\r\n";
write(cd, greeting, strlen(greeting));
}
close(cd);
} /* for (;;) */
} /* main */
你的服务器理解这一点,客户的意思以为它连接?它是如何显示的?究竟发生了什么? –
OT:这个......接受(...,(socklen_t *)&c)'是坏的。想象一下'int'和'socklen_t'将会有不同的大小!直接将'c'定义为'socklen_t'。 – alk
OT:当服务器开始发送“更大”的数据量时,这个'if(recv(sock,server_reply,2000,0) alk