I'm making a multithreaded tcp server for a game.
I'm having trouble with sockets, when the server stops recieving information from the client, I close that socket i did accept() (shown below) on and exit the thread and inform the main thread that the slot is not busy anymore.
clientData.client[next] ) = accept(server,(struct sockaddr *)&client_address,&t));
(error check ommitted here but i do have it)
However when I try to enter that slot again it gives me a bad file descriptor, I did some digging and found out that close() completely destroys a socket and renders it unusable for the rest of the run(please correct me if I'm wrong).
Now what makes me confused is that:
a) I can still use the socket to accept, and I get back a file descriptor, the problem is when i try to use recv() on the socket like this.
n = (recv(c->client[threadLocal], str, 100, 0);
(error check ommitted here but i do have it)
b) I can reuse the socket fine and dandy when I get to the last slot in my socket array which is just weird, if its a problem the first runs but not the last i get the feeling I've miss understood something.
c) How can i make a socket reusable? Or what is a good alternative to making sockets that can be reused for the rest of the program run.
All help is GREATLY appriciated, because honestly im so confused about whats going on here.
EDIT: Okay so a small example of what im trying to do. I have an array of sockets in a struct which represent slots on the server. I realised it would probably have been easier to do a list of structs that represent players that contain a socket, so you can make a new struct when someone joins but i'd rather not right now because that would require a lot of work, but if there is no option i will do it.
struct clientData{
int clientSocket[maxplayers];
//and some other stuff
};
When a player joins they take the first available socket in the list and does accept() on it, when the client disconnects I want the socket to be available for another client to claim. basically I want the old client to let go with close() or something similiar and the new client who connects later to be able to reuse this socket/position in the array.
Im looking for a way to reset a socket so it can be used again when needed. I hope this made things more understandable, thanks again.
-
1I do not understand why are you trying to reuse a closed socket.SergeyA– SergeyA2016年04月27日 17:06:35 +00:00Commented Apr 27, 2016 at 17:06
-
Your question really doesn't make sense. Post a minimal reproducible example.Gil Hamilton– Gil Hamilton2016年04月27日 17:24:26 +00:00Commented Apr 27, 2016 at 17:24
-
Additionally to providing an MCVE, it reads a bit like you mix up the listen sockets and the (accepted) connection sockets very much here. Please make a clear distinction here in your question.Ctx– Ctx2016年04月27日 17:57:45 +00:00Commented Apr 27, 2016 at 17:57
-
Sorry for being bad at explaining, its been a loong day. I tried to make it more clear what the problem is, thanks for answering all of you.D. O.– D. O.2016年04月27日 18:50:26 +00:00Commented Apr 27, 2016 at 18:50
-
well i have a socket called server that i do the socket and listen functions on, then i have sockets that i accept onD. O.– D. O.2016年04月27日 19:14:34 +00:00Commented Apr 27, 2016 at 19:14
1 Answer 1
You are confusing two different types of sockets.
There are listening sockets. You make a socket into a listening socket when you call listen. You can then call accept on the listening socket to get connected sockets. The only time you would close a listening socket is if you don't want to listen for new connections any more (at least, not on that port). You would never call send or recv on a listening socket because they're not connected to anything.
There are connected sockets. When you call accept on a listening socket, you get back a brand new connected socket. You can call send and recv on the connected socket to talk to the other end. When you're done with a connected socket, you should close it. Then the connected socket will be fully destroyed.
You can continue to call accept on a listening socket to get more connected sockets as you call send, recv, and close on those connected sockets as you need to do that to manage your various connections.
You may also be confusing sockets with socket handles. Sometimes people do use the term "socket" for both. But there is the socket itself, which is a communication endpoint that may or may not be connected and then there's the socket handle which is a number that is used to reference a specific socket.
You cannot reuse the actual socket -- it's the endpoint of a dead connection. You can re-use the socket handle. Once you call close, regardless of what happens to the actual socket, the handle can be reused. Your next call to socket or accept may get back the same handle. (But don't assume it does, just store the handle.)
When a player joins they take the first available socket in the list and does accept() on it, when the client disconnects I want the socket to be available for another client to claim. basically I want the old client to let go with close() or something similiar and the new client who connects later to be able to reuse this socket/position in the array.
The new client can reuse the socket handle and the position in the array. Call accept on your listening socket and store that new connected socket's handle in the vacant array slot.
I'm assuming your first sentence is worded a bit badly. I suspect what you mean to say is something like: "For a player to join the server, a slot in the array is assigned. A thread calls accept on the server's listening socket and stores the returned socket descriptor in that slot in the array."
When you're done with a connection, close the connected socket and mark that slot in the array free. You can then call accept again on the listening socket, maybe get back the same socket descriptor, but either way store the new connected socket in that slot in the array and handle the new client.
7 Comments
close the socket handle that refers to the connected socket. This has no effect on the listening socket, so of course you can call accept on it again. Read the sentence that begins "You can continue to call accept" again.server is the listening socket and client is the connected socket. So you need to call accept on server, not client. You want client=accept(server);. You want to assign to client the descriptor for a socket that represents the connection you accepted on the listening socket server.