I've got some new troubles for you. I'm studying sockets and TCP/IPv4 in C. I have to write a battleship game and I'm quite excited about it. But I can't really solve some problems. So this is my situation.
I've got one server and multiple clients. Each client can challenge or be challenged from another client. The server waits for a client to write an univoque ID. Once the ID is written, the server scans an array of struct sockaddr and finds the one related to the previously read ID. Then it calls inet_ntoa() to make the IP a string and writes it to the client. Once the client has read the IP, it creates a new direct connection with the other client and starts playing battleship.
Okay so this is the scenario. What I'm struggling with, is first how to get a univoque IP address out of that inet_ntoa(), since I'm executing every client instance in a terminal on the same host machine. Second, every client should accept incoming connections from other clients. So I gave each client 2 sockets: one for the client-server communication, and one that listens for the possible pending connections (This socket will be put in a readfd of a select() ). The thing is, once I start a new client istance -if another client is already connected and waiting to challenge or be challenged - I have to specify the IP of the server the client will connect to. So, whether I use 127.0.0.1 or the host machine IP address, the new istance of the client tries to connect to the already connected client (since its socket is in a listen state) and not to the server. I think it has to do with ports, but I don't know how to achieve what I want to do (Already tried to change ports etc.).
Here are some lines of the code. I omitted obvious things (don't kill me for this last sentence, please).
CLIENT CODE:
struct sockaddr_in servaddr, claddr,cl2addr;
servaddr.sin_family=AF_INET; //used for the client-server connection
servaddr.sin_port=htons(8888); //port 8888 for the client-server communication
servaddr.sin_addr.s_addr=inet_addr(argv[1]); //argv[1]=IP of the server
cl2addr.sin_family=AF_INET; //this will be used for the client-client new connection
cl2addr.sin_port=htons(9990);//listen on the port 9990
cl2addr.sin_addr.s_addr=INADDR_ANY; //for any client to connect
servsock=socket(PF_INET,SOCK_STREAM,0);
listenfd=socket(PF_INET,SOCK_STREAM,0);
if (bind(listenfd,(struct sockaddr*)&cl2addr,sizeof(cl2addr))<0)
{
perror("Binding: "); //This printf "Address already in use"
exit(-1);
}
if (listen(listenfd,1)<0)
{
perror("Listening: ");
exit(-1);
}
if (servsock<0)
{
perror("Creating socket: ");
exit(-1);
}
if (connect(servsock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) //estabilish a connection with the main server
{
perror("Connect: ");
exit(-1);
}
//some code with the select etc. inside //
if ((mastfd=accept(listenfd,(struct sockaddr *) &claddr,&cllen))<0)
{
perror("Accept: ");
exit(-1);
}
SERVER CODE:
struct sockaddr_in servaddr, claddr[10]; //che claddr array holds every IP in the sin_addr.s_addr field
int conn=0;
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(8888);
servaddr.sin_addr.s_addr=INADDR_ANY;
listenfd=socket(PF_INET,SOCK_STREAM,0);
if (listenfd<0)
{
perror("Socket: ");
exit(-1);
}
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt))<0)
{
perror("setsockopt");
exit(-1);
}
if (bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr))<0)
{
perror("Bind: ");
exit(-1);
}
if (listen(listenfd,10)<0)
{
perror("Listen: ");
exit(-1);
}
//here goes a while loop//
{
FD_SET(listenfd,&readfd);
select(maxfd,&readfd,NULL,NULL,&elaps);
accept(listenfd,(struct sockaddr *)&claddr[conn],&len);
conn++;
//here the server waits for a client to write the ID to challenge, find the relative position in the claddr array and then writes the ip to the client//
m=strlen(ipbuff); //calculate the lenght of the IP
nwrite=write(att,&m,sizeof(m)); //write the lenght to the client
if (nwrite<0)
{
perror("Writing LEN: ");
_exit(-1);
}
nwrite=write(att,ipbuff,m); //write the IP to the client
if (nwrite<0)
{
perror("Writing IP: ");
_exit(-1);
}
}
Ps.
Very often, the IP written from server to client has len=2 and is something like 00 or 0.0.0.0 . This is due to the fact that it returns the local machine ip address, right?
Thank you guys, by the way. If code is bad indented or other things, feel free to throw s*** on me.
Related
i am trying to implement 1 "Server" (broker) and 2 "Clients" in C with UDP Sockets. But i cant get it to work.
What is my Goal:
One of the clients (CLIENT A) can send a word to the Server and the server saves that word in a char[]. After that, everytime if the other Client (CLIENT B) sends a message to the server, and the word of Client A is contained in that message, the whole message will be sent to CLIENT A. If the word isnt in the message, nothing will happen.
The Implementation of the server without multiple Client A´s is no problem. But i cant get it to work with multiple Client A´s.
Lets face the problem:
The Server is listening with a select() to potential Client A and Client B.
if client B is sending a keyword, the code is doing the following:
if(FD_ISSET(server_cli, &server_fd)){
client_length = sizeof(client_addr);
bzero(buffer, sizeof(buffer));
nbytes = recvfrom(server_cli, buffer, sizeof(buffer), 0, (struct sockaddr *) &client_addr, &client_length);
memcpy(&save_ip[counter].client_address, &client_addr, sizeof(client_addr));
strcpy(save_ip[counter].topic, buffer);
fprintf(stderr, "\n[+] Subrequest from: %s - Topic: %s", inet_ntoa(save_ip[counter].client_address.sin_addr), save_ip[counter].topic);
counter = counter + 1;
}
save_ip[counter].client_address is a struct in an array (dont know how that is called - i am relatively new to C). Everytime a Client is sending a keyword, the counter is counter + 1 and the client- socket information from the struct i get from recvfrom() will be saved in there (that is the plan and that is working..)
if Client A is sending a message and the message contains the keyword of any of Client B´s it will do something like that:
else if( !strcmp( pub_topic, save_ip[temp_counter].topic )){
client_addr = save_ip[counter].client_address;
fprintf(stderr, "\nIP: %s", inet_ntoa(client_addr.sin_addr));
nbytes = sendto(server_cli, buffer, sizeof(buffer), 0, (struct sockaddr *) &save_ip[counter].client_address, sizeof(save_ip[counter].client_address));
fprintf(stderr, "\n\t[+] Sent Message to %s (User-Topic: %s)", inet_ntoa(save_ip[temp_counter].client_address.sin_addr), save_ip[temp_counter].topic);
So, as you can see... I am trying to save the sockaddr structs from clients in this:
struct clients {
struct sockaddr_in client_address;
int client_length_long;
char topic[512];
};
But that doesnt work at all. I can get IP Addresses and everything else from the struct (and the values are correct), but i cant integrate them in a sendto(). Nothing is received by Client B.
Is there any other/better solution? (Mine is not a solution - it doesnt work at all). Can you guys advice me something to get it to work?
I'm working with TCP servers. Let's say I have a server running with a specific port, but then I want to connect a client to it, I would simply go through the typical procedure of socket, bind, listen, accept for the server and then socket, connect for the client. So let's say our server port is 4000, and our client port 4001. Now, I want to create a new client that will connect to my client on port 4001, but to my limited understanding, I cannot do this as a client. Port 4001 would have to pertain to a server and not a client (i.e. it would have to be listening). The issue arises because I don't think you can use the same port for both the server and client.
I've decided to attempt this through the sample code I've provided below. I call the program on the command line as follows:
If this is the first call of the server, then I simply call the program without any arguments and it will automatically run on port 3000. i.e. ./serverprogram
If I would like to connect a client on port 3001 to our server on port 3000. Then I would call the command line with two arguments, the first being 3001 and the second being 3000. i.e. ./serverprogram 3001 3000
#define PORT 3000
int main (int argc, char * argv[]){
int sfd = socket(AF_INET, SOCK_STREAM, 0);
int my_port = (argc == 3) ? atoi(argv[1]) : PORT;
if (argc > 2){
struct sockaddr_in c_addr;
c_addr.sin_family = AF_INET;
memset(&c_addr.sin_zero, 0, 8);
c_addr.sin_port = htons(atoi(argv[2]));
struct addrinfo *result = NULL;
getaddrinfo("AcaciaLinux", NULL, NULL, &result);
struct sockaddr_in *x = (struct sockaddr_in*) result->ai_addr;
c_addr.sin_addr = x->sin_addr;
freeaddrinfo(result);
if(connect(sfd, (struct sockaddr *) &c_addr, sizeof(struct sockaddr_in)) == -1){
perror("connect");
exit(1);
}
printf("We have connected to a server.");
}
if (sfd == -1){
perror("socket");
exit(1);
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(my_port);
saddr.sin_addr.s_addr = INADDR_ANY;
memset(&(saddr.sin_zero), 0, 8);
if(bind(sfd, (struct sockaddr*) &saddr, sizeof(struct sockaddr_in)) == -1){
perror("bind");
close(sfd);
exit(1);
}
if (listen(sfd, 5) < 0){
perror("listen");
exit(1);
}
struct sockaddr_in caddr;
saddr.sin_family = AF_INET;
int cfd;
unsigned int c_len = sizeof(struct sockaddr_in);
if ((cfd = accept(sfd, (struct sockaddr*) &caddr, &c_len)) == -1){
perror("accept");
exit(1);
}
printf("Alas, we have finally connected to a client.");
return 0;
}
Upon running the second instance of the program I receive the error "bind: Invalid argument". I am assuming that this is due to the fact that the port is already in use. Is there any way to bypass this, or is there any way to connect a server to a client, and allow the client to also act as a server using the same port
You cannot open a socket which can do the both listen and connect.
A TCP connection is identified by its two endpoints. Each of those, in turn, is identified by an (IP address, port) pair. Therefore, you cannot simultaneously have two distinct connections between the same two IP addresses with the same ports on each end -- if all of those properties are the same, then they are the same connection.
From the perspective of system interfaces, you cannot create that situation because the system will not allow you to bind an address / port pair that is already in use to any socket (a stronger constraint than is strictly required). This means that one machine cannot use the same port simultaneously for both a client socket and a server socket, even for different remote endpoints.
You can, however, have any number of simultaneous TCP connections that each differ from all the others in at least one of those parameters. In particular, you can have any number of connections between the same two machines, with the same port on one side, and different ports on the other. This is extremely common, in fact, as web browsers often open multiple simultaneous connections to a web server to download multiple resources concurrently. All of those connections have the same server address, server port, and client address, but different client port.
If you want to have multiple simultaneous connections that are associated with one another in some way that goes beyond IP addresses, then you'll need to develop a protocol for it that involves multiple ports at at least one end. If the machines make reciprocal connections, with A connecting to B and then B connecting, separately, to A, then you'll need different ports on both sides. The port numbers to use might be fixed by the protocol or negotiated in some way, at your discretion, but the specifics described in the question are not an option.
i have simple client/server app with socket , so the client connect to the server with the server ip , i want to return ip of connected client with inet_ntoa but it always returns false ip of connected client. why ? and how to solve it .
i want the server to return true ip of machine connected to scan open ports later
struct sockaddr_in addr_remote;
...
connfd = accept(sockfd, (SA*)&cli, &len);
...
printf( " Welcome %s " , inet_ntoa(addr_remote.sin_addr));
You use inet_ntoa with addr_remote. addr_remote is never set in your code and therefore the contents is kind of unpredictable. You probably intended to use addr_remote inside accept but you've used cli there.
This question already has answers here:
Detecting TCP Client Disconnect
(9 answers)
Closed 4 years ago.
I have basic tcp application written in C. It basically sends data to a tcp server. I have connected two PC's with cross cable. I send data from one, and successfully get this data from another one. I have built this mechanism to test If somehow connection broken by unhealty ways (ruptured cable etc.), I want to be informed as client. But things doesn't work as I wanted.If I manually stop tcpserver, client side is informed, but when I start program, connection establishes, data starts to flow, then I unplug the cable, and both sides behaves like nothing happened. Client still sends data with no error, and server still shows the client connected but data flow stops. After a few minutes, I plug cable again, the datas -which considered as sent but not sent- flushes suddenly then program continues normally. How can I detect a broken connection like this? Any help would be appreciated. Here is the code;
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int main() {
const char* server_name = "192.168.5.2";
const int server_port = 30152;
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
// creates binary representation of server name
// and stores it as sin_addr
// http://beej.us/guide/bgnet/output/html/multipage/inet_ntopman.html
inet_pton(AF_INET, server_name, &server_address.sin_addr);
// htons: port in network order format
server_address.sin_port = htons(server_port);
// open a stream socket
int sock;
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("could not create socket\n");
return 1;
}
// TCP is connection oriented, a reliable connection
// **must** be established before any data is exchanged
if (connect(sock, (struct sockaddr*)&server_address,
sizeof(server_address)) < 0) {
printf("could not connect to server\n");
return 1;
}
// send
// data that will be sent to the server
const char* data_to_send = "HELLO THIS IS DATA!";
while(1)
{
int err = send(sock, data_to_send, strlen(data_to_send), 0);
if(err==-1)
{
printf("ERROR \n");
break;
}
else
{
printf("sent \n");
sleep(1);
}
}
printf("EOP\n");
// close the socket
close(sock);
return 0;
}
If the peer of a TCP connection closes the connection, it will lead to a recv call on your end to return 0. That's the way to detect closed (but not broken) connections.
If you don't currently receive anything from the peer, you need to make up a protocol on top of TCP which includes receiving data.
Furthermore, sending might not detect broken connections (like missing cables etc.) directly, as there are a lot of retransmissions and timeouts. The best way is again to implement some kind of protocol overlaying TCP, one that for example contains a kind of "are you there" message which expects a reply. If a reply to the "are you there" message isn't received within some specific timeout, then consider the connection broken and disconnect.
accept() is defined to always create another file descriptor to accept new connections from the client, but if it is known beforehand that we are only going to be accepting one client and one connection, why bother with creating a new file descriptor? Are there any descriptions of why this is the case in any defined standards?
When designing APIs I think there is value in being generic. Why have 2 APIs, one for accepting potentially multiple connections and one for using fewer file descriptors? The latter case doesn't seem high priority enough to justify an entirely new syscall when the API we have today will do and you can use it to implement the behavior you want just fine.
On the other hand, Windows has AcceptEx which lets you re-use previous socket handles that previously represented otherwise unrelated, previously connected sockets. I believe this is to avoid the performance hit of entering the kernel again to close sockets after they are disconnected. Not exactly what you are describing but vaguely similar. (Though meant to scale up rather than scale down.)
Update: One month later I think it's a little strange that you created a bounty on this. I think the answer is clear - the current interfaces can do what you ask for just fine and there's really no motivation to add, let alone standardize, a new interface for your fringe case. With the current interfaces you can close the original socket after accept succeeds and it won't harm anyone.
The TCP protocol described in RFC 793 describes the terms socket and connection. A socket is an IP address and port number pair. A connection is a pair of sockets. In this sense, the same socket can be used for multiple connections. It is in this sense that the socket being passed to accept() is being used. Since a socket can be used for multiple connections, and the socket passed to accept() represents that socket, the API creates a new socket to represent the connection.
If you just want an easy way to make sure the one socket that accept() creates for you is the same socket you used to do the accept() call on, then use a wrapper FTW:
int accept_one (int accept_sock, struct sockaddr *addr, socklen_t *addrlen) {
int sock = accept(accept_sock, addr, addrlen);
if (sock >= 0) {
dup2(sock, accept_sock);
close(sock);
sock = accept_sock;
}
return sock;
}
If you are wanting a way for a client and server to connect to each other, without creating any more than just one socket on each side, such an API does exist. The API is connect(), and it succeeds when you achieve a simultaneous open.
static struct sockaddr_in server_addr;
static struct sockaddr_in client_addr;
void init_addr (struct sockaddr_in *addr, short port) {
struct sockaddr_in tmp = {
.sin_family = AF_INET, .sin_port = htons(port),
.sin_addr = { htonl(INADDR_LOOPBACK) } };
*addr = tmp;
}
void connect_accept (int sock,
struct sockaddr_in *from, struct sockaddr_in *to) {
const int one = 1;
int r;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
bind(sock, (struct sockaddr *)from, sizeof(*from));
do r = connect(sock, (struct sockaddr *)to, sizeof(*to)); while (r != 0);
}
void do_peer (char *who, const char *msg, size_t len,
struct sockaddr_in *from, struct sockaddr_in *to) {
int sock = socket(PF_INET, SOCK_STREAM, 0);
connect_accept(sock, from, to);
write(sock, msg, len-1);
shutdown(sock, SHUT_WR);
char buf[256];
int r = read(sock, buf, sizeof(buf));
close(sock);
if (r > 0) printf("%s received: %.*s%s", who, r, buf,
buf[r-1] == '\n' ? "" : "...\n");
else if (r < 0) perror("read");
}
void do_client () {
const char msg[] = "client says hi\n";
do_peer("client", msg, sizeof(msg), &client_addr, &server_addr);
}
void do_server () {
const char msg[] = "server says hi\n";
do_peer("server", msg, sizeof(msg), &server_addr, &client_addr);
}
int main () {
init_addr(&server_addr, 4321);
init_addr(&client_addr, 4322);
pid_t p = fork();
switch (p) {
case 0: do_client(); break;
case -1: perror("fork"); exit(EXIT_FAILURE);
default: do_server(); waitpid(p, 0, 0);
}
return 0;
}
If instead you are worried about performance issues, I believe those worries are misguided. Using the TCP protocol, you already have to wait at least one full round trip on the network between the client and the server, so the extra overhead of dealing with another socket is negligible. A possible case where you might care about that overhead is if the client and server are on the same machine, but even then, it is only an issue if the connections are very short lived. If the connections are so short lived, then it would probably be better to redesign your solution to either use a cheaper communication medium (e.g., shared memory), or apply framing on your data and use a persistent connection.
Because it isn't required. If you only have one client, you only do the operation once; you have plenty of file descriptors to spare; and compared to network overheads the 'overhead' is vanishingly small. The case that you would want to 'optimize' as an API designer is when you have thousands of clients.
The only thing that changes between the socket returned by listen and the socket descriptor returned by accept, is that the new socket is in the ESTABILISHED state instead of the LISTEN state.So you can re-use the socket created after invoking the listen functions to accept other connections.
As accept() is designed to accept new client .
it required three things, general socket descriptor which must bind to a specific port number for serving at that port number and a structure to store the client information and another int value to store size of client .
it return a new_socket_descriptor for serving the particular client which is accepted by server.
the first parameter is a socket descriptor used to accept client.And for concurrence server, it is always use for accepting client connection .So it should not modify by any accept() call.
so new socket descriptor returned by accept() to serve new connected client.
the server socket descriptor(1st parameter) bind to server property.server property always designed to a fixed type that is its port number ,type of connection,protocol family all are fixed.So same file descriptor is used again and again.
Another point is that these property are used to filter client connection which are made for that particular server.
For clients,information for each client different minimum ip address used by every client unique and these property are bind to new file descriptor so always a new file descriptor returned by accept() function success.
NOTE:-
that is you require one file descriptor must for client accepting and depending upon maximum number of client you want to accept/serve use that much file descriptor for serving clients.
The answer is that your specific example of exactly one connection is handled in the current API and was designed into the API's use cases from the start. The explanation for how the single socket case is handled lies in the way socket programs were designed to work when the BSD socket interface was first invented.
The socket API was designed to always be able to accept connections. The fundamental principle is that when a connection arrives, the program should have the final decision as to whether the connection is accepted or not. However, the application must also never miss a connection while making this decision. Thus, the API was designed only to be parallel and accept() was specified to return a different socket from listen(), so that listen() could continue listening for further connection requests while the application made its decision about the connection request just received. This was a fundamental design decision and is not documented anywhere; it was just assumed that socket programs would have to work that way in order to be useful.
In the old days before threads were invented, the parallelism required to implement socket servers on Unix-like systems relied on fork(). A new connection was accepted, the program would split itself into two identical copies using fork(), and then one copy would handle the new connection while the original copy continued listening for incoming connection attempts. In the fork() model, even though accept() returns a new file handle, the use case of handling exactly one connection was supported and was achieved by just letting the "listening" copy of the program exit while the second "accept" copy handles the single connection.
The following pseudo code shows this:
fd = socket();
listen(fd, 1); /* allow 1 unanswered connection in the backlog */
switch (fork())
{
case 0: break; /* child process; handle connection */
case -1: exit (1); /* error. exit anyway. */
default: exit (0); /* parent process; exit as only one connection needed */
}
/* if we get here our single connection can be accepted and handled.
*/
accept_fd = accept(fd);
This programming paradigm meant that whether servers accepted a single connection, or stayed in loops handling multiple connections, the code was virtually identical in both cases. Nowadays we have threads instead of fork(). However, as the paradigm still remains to this today, it has never been necessary to change or upgrade the socket API.