all. I'm having a bit of weird problem with client server program. I have two different kinds of clients trying to connect to one server, one is just more barebone than the other with less things to do. But other wise they are practically the same. While the barebone code can connect to server and server accepts it fine, the elaborate version of it can't. The client says it's connected, sends messages (via both send() and sendto()) and gets number of bytes sent back. But the server doesn't recognize it. I'm not really sure why, esp upon comparing both versions of clients, they are really the same thing (at least until connect() is called), elaborate version has bind() whereas barebone version doesn't. Can anybody see a problem as to why these very similar codes don't work similar :P
if (argc == 3)
{
host = argv[1]; // server address
info.c_name = argv[2];
}
else
{
printf("plz read the manual, kthxbai\n");
exit(1);
}
hp = gethostbyname(host);
if (!hp)
exit(1);
printf("host found\n");
// setting up address and port structure information
bzero((char * ) &server_address, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(SERVER_PORT);
// opening up socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
exit(1);
else
printf("socket is opened: %i \n", sockfd);
info.sock_fd = sockfd;
// binding socket to a port: not in barebone version
rv = bind(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
if (rv < 0)
{
printf("MAIN: ERROR bind() %s\n", strerror(errno));
exit(1);
}
else
printf("socket is bound\n");
// connecting
rv = connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
printf("rv = %i\n", rv);
if (rv < 0)
{
printf("MAIN: ERROR connect() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("connected\n");
I'm not even sure where the problem is, whether it's the elaborate version of client or it's just the server? Thanks for any enlightenment.
If the code is really what you're using, your client is (magically!) connecting to itself, due to TCP's somewhat obscure Simultaneous connect support.
The problem here is that you aren't using the return for gethostbyname at all.
You also shouldn't bind the server port if it might be running on the local machine.
Related
I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.
I'm trying to test a client-server simple implementation using localhost address.
Here's the code.
Server:
/*
* Sequential busy-waiting
*/
int main(int argc, char** argv) {
int opt, client_addr_l, errsv;
unsigned short port;
struct sockaddr_in server_addr, client_addr;
/* ... */
printf("Port number retrieved (%d), server is starting ...\n", port);
/*TCP Socket creation*/
sock_ds = socket(AF_INET, SOCK_STREAM, 0);
if(sock_ds == -1){
fprintf(stderr, "Socket creation error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
/*Server address binding*/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
/*!!!! */
int optval = 1;
if( (setsockopt(sock_ds,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval))) == -1 ) {
printf("Error on setsockopt\n");
exit(EXIT_FAILURE);
}
/*????*/
if(bind(sock_ds, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
fprintf(stderr, "Address binding error\n");
exit(EXIT_FAILURE);
}
/*Server with passive socket*/
if(listen(sock_ds, SOMAXCONN) == -1){
fprintf(stderr, "Listen call error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
while(1){
memset(&client_addr, 0, sizeof(client_addr));
acc_sock_ds = accept(sock_ds, (struct sockaddr *)&client_addr, &client_addr_l);
printf("DEBUG: LINE201, acc_sock_ds = %d\n", acc_sock_ds);
/*Connect error management*/
if(acc_sock_ds == -1){
fprintf(stderr, "Fatal error on accept %d(%s)\n"
, errsv, strerror(errsv));
exit(EXIT_FAILURE);
}
//sin_addr to ASCII (string) );
printf("Connected with: %s\n", inet_ntoa(client_addr.sin_addr));
/*...*/
close(acc_sock_ds);
/*...*/
}
/*...*/
}
Client:
int main(){
int sock_ds;
struct sockaddr_in remote_addr;
struct hostent *hp;
/*TCP Socket creation*/
sock_ds = socket(AF_INET, SOCK_STREAM, 0);
if(sock_ds == -1){
fprintf(stderr, "Socket creation error\n");
exit(EXIT_FAILURE);
}
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(25556);
hp = gethostbyname("localhost");
bcopy(hp -> h_addr, &remote_addr.sin_addr, hp -> h_length); //fills address entry
if(connect(sock_ds, (struct sockaddr*)&remote_addr, sizeof(remote_addr)) == -1){ //connection attempt
fprintf(stderr, "Connect failure(%s)\n", strerror(errno));
exit(EXIT_FAILURE);
}
/*...*/
}
When i run them on two different terminals server returns me:
Port number retrieved (25556), server is starting ...
Server is ready. Waiting for client connections.
DEBUG: LINE201, acc_sock_ds = 4
Connected with: 0.0.0.0
My question is: why does the client address retrieved by the server is 0.0.0.0. It should not be 127.0.0.1?
It looks like you are passing the third parameter to accept() uninitialized, it should be set at the size of the second parameter. In addition to that, it should be a socklen_t, not an int, see http://pubs.opengroup.org/onlinepubs/009695399/functions/accept.html
Could try by declaring client_addr_l as a socklen_t, then setting it to sizeof( struct sockaddr_in) before passing to accept() ?
I'm guessing its unitialized value is zero, so accept() cannot set the remote address to your client_addr as it has a zero size. So, client_addr is untouched and, as you zeroed it earlier, you get 0.0.0.0.
0.0.0.0 means that your server accept connection from any interface in your equipment
so the loopback interface with the address 127.0..0.1 is included
It seems to be a special situation. All possible addresses are listening for your connection.
Here is a thread on this.
Quote:
0.0.0.0, in this context, means "all IP addresses on the local machine"
(in fact probably, "all IPv4 addresses on the local machine").
So, if your webserver machine has two ip addresses, 192.168.1.1 and 10.1.2.1,
and you allow a webserver daemon like apache to listen on 0.0.0.0,
it will be reachable at both of those IPs.
But only to what can contact those IPs and the web port(s).
server_addr.sin_addr.s_addr = INADDR_ANY;
probably should be
server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
I'm making a client program in C that has to deal with this situation:
1- server program receives udp datagram in port no 8080 sent by client with a port number X
2- server creates a new socket (TCP) in port number X
3- using this TCP socket, server reads a string sent by the client
(running on localhost)
I don't need to make the server program, it's already done. The points 1 and 2 are covered, but I've been a couple of days trying to work out the 3rd point and I'm not able to make it work ><
The code I've got for the client is this:
#define MYPORT 8080
int main(int argc, char *argv[ ]) {
int sockfd;
/* connector’s address information */
struct sockaddr_in their_addr;
struct hostent *he;
int numbytes;
int sockfd2, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc != 3) {
fprintf(stderr, "Usage: %s <hostname> <message>\n", argv[0]);
exit(1);
}
/* get the host info */
if ((he = gethostbyname(argv[1])) == NULL) {
perror("Error obtaining the client. \n");
exit(1);
}
else printf("Client obtained\n");
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Error creating UDP socket\n");
exit(1);
}
else printf("UDP Socket done\n");
their_addr.sin_family = AF_INET;
printf("Port: 8080\n");
their_addr.sin_port = htons(MYPORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8);
sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd2 < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
//sending port where the TCP socket will be associated
//server client connects correctly to this port
//and the code it's working fine in this point
if((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
{
perror("Client-sendto() error lol!");
exit(1);
}
//port is sent, now let's connect to the port by tcp and write the string
//not working properly from now on
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(atoi(argv[2]));
if (bind(sockfd2,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
//sending the string to the TCP Port...
if((numbytes = sendto(sockfd2, "hi", 2, 0, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr))) == -1)
{
printf("Client-sendto()-TCP error\n");
exit(1);
}
if (close(sockfd) != 0) printf("Client-sockfd-UDP closing is failed!\n");
else printf("Client-sockfd-UDP successfully closed!\n");
if (close(sockfd) != 0) printf("Client-sockfd2-TCP closing is failed!\n");
else printf("Client-sockfd2-TCP successfully closed!\n");
return 0;
}
The code works for the first two steps, but in the last step, it seems it's not connecting well with the TCP port, because my client program ends but my server program says that he receives null.
And of course I'm always sending ports > 1024
Thanks in advance, any help will be so appreciated.
listen(sockfd2, 5);
accept(sockfd2, 0, 0);
printf("accepted!\n");
I haven't read all your code, but the above (at least) is wrong. You absolutely need to retain the return value of accept: it's the socket you need to write to!
accept returns a file descriptor for the new TCP socket that has just been created for communicating with the "server" in your case. You need to use that as the file descriptor you write your string to.
(The sendto call just after that, apart from using the wrong socket, is a bit suspicious since the server will have no way to determine how much data to read/where the message stops. Passing a length of 3 (to include the \0 byte, would be a bit less suspicious.)
This is the main code of my server program in C:
int main(int argc, char** argv)
{
int sock, connected, bytes_received, true = 1;
struct sockaddr_in server_addr, client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Socket");
exit(1);
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (int)) == -1) {
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[1]));
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);
if (bind(sock, (struct sockaddr *) &server_addr, sizeof (struct sockaddr))
== -1) {
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1) {
perror("Listen");
exit(1);
}
printf("\nTCPServer Waiting for client on port 5000");
fflush(stdout);
while (1)
{
pthread_t child;
sin_size = sizeof (struct sockaddr_in);
connected = accept(sock, (struct sockaddr *) &client_addr, &sin_size);
printf("\n I got a connection from (%s , %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
threadInfo info;
info.argumentsPassedToCode = argv;
info.connected = connected;
pthread_create(&child, NULL, interpretMessage, &info);
}
close(sock);
return 0;
}
My server always prints out the IP of the incoming connection, and the port that it is coming in from. I noticed that the ports are always increasing.
Is this normal? If not, what am I doing wrong?
If my server runs for a long time, will it run out of ports? If so, what will happen?
If your server is working, you're not doing anything wrong. Source ports aren't guaranteed to follow a pattern, they just exist to complete the connection tuple, (source port, source address, dest port, dest address).
Ports are reused once connections close, so you should be okay.
TCP has a state called TIME_WAIT which is used to make sure that everything have been sent and received properly before cleaning up the socket. This happens after you have closed the socket in you code. The time that a socket is in the TIME_WAIT state depends on the OS.
That's why you don't get the same port again for client connections.
You can read more about the state here: https://stackoverflow.com/questions/41602/how-to-forcibly-close-a-socket-in-time-wait
1) Yes; the next available port is selected. It can be the same port (if the prev socket was freed already by kernel), it can be the next free one or any other port which is free, from 1024 to 65535 (first 1024 are reserved as you know); In your case you are seeing a different client port number because either you are not properly closing the client socket or the previous socket is still lingering when you are making the next connection or you are just making multiple parallel connections
2) If you are not properly shutting down the sockets, you will (probably first run out of file descriptor if you have lower default per-process limits which is ... 1024 fds per proc?) ; If you do tear them down correctly then you'll be fine
Hey all, I'm about to rip my hair out. I have this client that tries to connect to a server, everything seems to be fine, using gethostbyname(), socket(), bind(), but when trying to connect() it just hangs there and the server doesn't see anything from the client. I know that the server works because another client (also in C) can connect just fine. What causes the server to not see this incoming connection? I'm at the end of my wits here. The two different clients are pretty similar too so I'm even more lost.
if (argc == 2) {
host = argv[1]; // server address
}
else {
printf("plz read the manual\n");
exit(1);
}
hserver = gethostbyname(host);
if (hserver) {
printf("host found: %p\n", hserver);
printf("host found: %s\n", hserver->h_name );
}
else {
printf("host not found\n");
exit(1);
}
bzero((char * ) &server_address, sizeof(server_address)); // copy zeroes into string
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(hserver->h_addr);
server_address.sin_port = htons(SERVER_PORT);
bzero((char * ) &client_address, sizeof(client_address)); // copy zeroes into string
client_address.sin_family = AF_INET;
client_address.sin_addr.s_addr = htonl(INADDR_ANY);
client_address.sin_port = htons(SERVER_PORT);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
exit(1);
else {
printf("socket is opened: %i \n", sockfd);
info.sock_fd = sockfd;
rv = fcntl(sockfd, F_SETFL, O_NONBLOCK); // socket set to NONBLOCK
if(rv < 0)
printf("nonblock failed: %i %s\n", errno, strerror(errno));
else
printf("socket is set nonblock\n");
}
timeout.tv_sec = 0; // seconds
timeout.tv_usec = 500000; // micro seconds ( 0.5 seconds)
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
rv = bind(sockfd, (struct sockaddr *) &client_address, sizeof(client_address));
if (rv < 0) {
printf("MAIN: ERROR bind() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("socket is bound\n");
rv = connect(sockfd, (struct sockaddr *) &server_address, sizeof(server_address));
printf("rv = %i\n", rv);
if (rv < 0) {
printf("MAIN: ERROR connect() %i: %s\n", errno, strerror(errno));
exit(1);
}
else
printf("connected\n");
Any thoughts or insights are deeply greatly humongously appreciated.
-Fourier
EDIT:
If the socket is NOT set on non-block, then it hangs.
If the socket is set on non-block, then I get ERROR connect() 115: Operation now in progress
[EINPROGRESS]
O_NONBLOCK is set for the file descriptor for the socket and the connection cannot be immediately established; the connection shall be established asynchronously.
I would also like to mention that the server and the client are running on computers next to each other, connected by like one router.
The gethostbyname() function produces addresses in network byte order, so you do not need to pass them through htonl(). Also, the hostent->h_addr entry is a pointer to the address. Replace this line:
server_address.sin_addr.s_addr = htonl(hserver->h_addr);
with:
memcpy(&server_address.sin_addr, hserver->h_addr, hserver->h_length);
I see you set your socket in O_NONBLOCK mode.
Thus connect must return -1 and set errno to EAGAIN according to the man page of connect.
You can then know when the connection succeeded using select() on the socket.
This is a very common pattern to control the connection timeout (because select() must be feed with a timeout).
Check whether you can connect with the program telnet (it accepts a server name and port number). If that works, the bug must be in your code. If telnet also hangs, then check your firewall settings.
If you want to connect twice from the same machine I can see the reason for your problem.
You are binding the clientsocket. Your code binds the client socket very specifically to a fixed port (the server port). This leaves the O/S NOT free in choosing an available port for making the connection FROM. If one process has the port allocated (it has succesfully bound() and connected() to the server) then the other process cannot use that same port.
If there is no compelling reason for sending traffic FROM a specific port, let the O/S find an available port by changing this line
client_address.sin_port = htons(SERVER_PORT);
to
client_address.sin_port = 0;