I know the question has been asked already, but i seem to be some kind of "special" since my code doesn't work.
Instruction is "bind with port 0 and use getsockname to get port". What am i doing wrong...
struct sockaddr_in sa;
sa.sin_port=htons(0);
sa.sin_addr.s_addr=htonl(INADDR_ANY);
sa.sin_family=AF_INET;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr *serverptr = (struct sockaddr*)&sa;
bind(sock, serverptr,sizeof(sa));
socklen_t s=sizeof(sa);
int g=getsockname(sock,serverptr,&s);
g always prints as 0.
EDIT: it was so much simpler, just sa.sin_port
Dumb question.
Most of Berkley Socket API functions use very simple convention: result returned is the operation success indication. So, zero means OK, negative means error. To play safe, you have always to check it, and your code lacks this verification for the socket(), bind(), and getsockname() calls:
...
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
// log the error, etc
return;
}
int res = bind(sock, serverptr, sizeof(sa));
if (res < 0) {
// log the error, etc
close(sock);
return;
}
socklen_t s = sizeof(sa);
res = getsockname(sock, serverptr, &s);
if (res < 0) {
// log the error, etc
close(sock);
return;
}
...
Related
I have simple TCP server program. After I close it with CTRL+C and restart again in some cases telnet client report me "connection refused". Why it happens not always, but just in some cases? Command ps shows nothing regarding my programm.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>
void printHex(char *bts);
int main() {
char str[100];
int listen_fd, comm_fd;
struct sockaddr_in servaddr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bzero( &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(22000);
printf("binding\n");
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
printf("listening\n");
listen(listen_fd, 10);
printf("accepting\n");
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
printf("accep done\n");
int cn = 0;
while(1) {
bzero(str, 100);
printf("will read\n");
int br = read(comm_fd, str, 100);
printf("read done\n");
if (br > 0) {
printHex(str);
} else if (br <= 0) {
comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);
printf("accep done\n");
}
printf("error %d \n", br);
}
}
void printHex(char *bts) {
char *s = bts;
int i = 0;
do {
printf("%02X ", (unsigned char) *bts);
} while (*++bts !=0);
printf("%s\n",s);
}
You should check all return values from system calls:
int res;
res = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (res == -1)
// handle error
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listed_fd == -1)
// handle error
Most likely you will find then that your code fails on a bind system call, which means you can't reuse socket on same IP address, protocol and port. You can change this using setsockopt call:
// allow to rebind
int reuseaddr_on = 1;
res = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
&reuseaddr_on, sizeof(reuseaddr_on));
if (res < 0)
{
stderr("Setting of SO_REUSEADDR on server's"
"socket failed");
}
You should also close a socket when you are done with it.
while(1)
{
// your loop
}
res = close(comm_fd);
if (res == -1)
// handle error
As Linux Programmer's Manual says on pages devoted to close call:
NOTES
Not checking the return value of close() is a common but nevertheless serious programming error. It is quite possible that
errors on a previous write(2) operation are first reported at the final close(). Not checking the return value when closing the file may lead to silent
loss of
data.
Always check the return values of your syscalls.
In this case,
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
fails with EADDRINUSE, because you didn't set SO_REUSEADDR on the socket before binding.
When you do CTRL-C and restart again, is the bind sucessful?
bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
You need to check the status of the bind call. In all likelihood, this has failed due to connection having moved to TIME_WAIT state in server. And from this follows the error "connection refused" in client.
Far the bind to be successful when the server is run immediately after CTRL-C, use the SO_REUSEADDR in your socket option. With this bind will be successful, as long as there isn't another program bound to the port.
I'm writting a simple socket server/client app.
I run into interesting problem. In my server code I call accept on non-blocking socket like this
while ((res = accept(m_sd, NULL, 0)) >= 0) { // There are new clients
... // Saving res as fd etc
}
Everything works perfectly - when there is a client, accept returns a valid file descriptor. However when a first client disconnects and second client connect, accept returns 0 - which is a valid FD, howerver all operation on this descriptor fails. This happens also for the next clients - accept is returning 0. After random number of clients, acceptr returns a "valid" (non-zero) descritpor, and than it repeats.
Note: When there are no clients, accept returns -1 as expected with errno EAGAIN - which is completly fine. When accept returns zero, errno is not set.
What could cause such a weird behavior?
Here's how I create server socket:
struct sockaddr_in serv_addr;
m_sd = socket(AF_INET, SOCK_STREAM, 0);
if (m_sd < 0){}
//Handle error
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
int optval = 1;
setsockopt(m_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
if (bind(m_sd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
// Handle error
}
fcntl(m_sd, F_SETFL, O_NDELAY); // Make socket non-blocking
listen(m_sd, 50);
And here's how I create client:
int rc;
struct sockaddr_in serveraddr;
struct hostent *hostp;
m_sd = socket(AF_INET, SOCK_STREAM, 0);
if (m_sd < 0)
// Handle error
memset(&serveraddr, 0, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(port);
hostp = gethostbyname(hostname.c_str());
if (hostp == NULL)
// Handle error
memcpy(&serveraddr.sin_addr, hostp->h_addr, sizeof(serveraddr.sin_addr));
// connect to serveraddr
rc = connect(m_sd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (rc < 0)
//Handle error
//set to nonblocking
fcntl(m_sd, F_SETFL, fcntl(m_sd, F_GETFL, 0) | O_NONBLOCK);
This is the code, where I wait for new data from any client:
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(timeout).count();
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(m_sd, &rfds);
int end = m_sd;
for (const auto& s : m_clients) {
end = std::max(end, s.second.m_sd);
FD_SET(s.second.m_sd, &rfds);
}
int retval = select(end + 1, &rfds, NULL, NULL, &tv);
if (retval == -1) {
// Error handling
}
return retval > 0; // There is pending data from client
Problem solved! I was accidentally closing fd 0 in my code, which caused this weird behaviour. Now everything works. Thanks for helping - you've showed me the right way
I am new to socket programming... I tried this server side program
#define BUFLEN 512
#define MYPORT 3456
void errorp(char* msg)
{
perror(msg);
exit(1);
}
int main()
{
struct sockaddr_in server, client;
int sock;
int slen = sizeof(server);
int clen = sizeof(client);
char *recvbuf, senbuf[BUFLEN] = {'h','e','l','l','o'};
if((sock = socket(AF_INET, SOCK_DGRAM, 0) == -1))
errorp("Socket creation failed");
printf("To the client: %s, %s", senbuf, " World");
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = MYPORT;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
if(bind(sock, (struct sockaddr*)&server, slen)==-1)
errorp("Socket Bind Failed");
if(recvfrom(sock, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &client, &clen) == -1)
errorp("recv from error");
printf("From the client: %s", recvbuf);
if(sendto(sock, senbuf, sizeof(senbuf), 0, (struct sockaddr*) &client, sizeof(client)) == -1)
errorp("Error in sending");
printf("To the client: %s", senbuf);
close(sock);
return 0;
}
There are no compilation errors but the output is
Socket Bind Failed: Socket operation on non-socket
To the client: hello, World
Please help me figure out where the mistake is?
and help get rid of it
The error message says it all: The socket isn't a (valid) socket.
This should make you look at the code creating the socket:
if((sock = socket(AF_INET, SOCK_DGRAM, 0) == -1))
The code above 1st compares the result of the call to socket() to -1 and then assigns the result of the comparison to sock. So it's either 0 or 1. And the result of the call to socket() is lost.
The code shall look like this:
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
as == binds tighter then =.
BTW, having used a Yoda-Conditition would have avoided such kind of "typo":
if (-1 == (sock = socket(AF_INET, SOCK_DGRAM, 0)))
Also at least clen shall be of type socklen_t as its address is passed, to have a value written into it, which will fail miserably if the size of the expected socklen_t would be different from an int (which the code shown passes).
if((sock = socket(AF_INET, SOCK_DGRAM, 0) == -1))
// \__________________________________/
You have your brackets in the wrong place. It's setting sock to a true/false value because == is "more binding" than =. It should instead be:
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
// \_____________________________________/
which sets sock to the return value from socket() and then compares that to -1.
You also have no backing storage for recvbuf which means your recvfrom(), once it starts working, will almost certainly do something bad.
So I am really stuck here, just trying to make a simple C program that gets the content of a webpage into a buffer, but I'm having some problems; consider the following:
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if(err != 0)
{
printf("could not find a usable winsock.dll");
return NULL;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("could not find a usable winsock.dll");
WSACleanup();
return NULL;
}
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in sa = { 0 };
sa.sin_port = htons(port);
sa.sin_addr.s_addr = inet_addr(ip);
connect(sock, (struct sockaddr*)&sa, sizeof(sa));
The variables ip, and port, are passed through from main. as you can see here:
readsite("http://www.pagetutor.com/html_tutor/index.html", "68.71.137.60", 80);
I get the error code "10047" from executing printf("\n%d", GetLastError()); directly below the line connect(sock, (struct sockaddr*)&sa, sizeof(sa)); and this code according to microsoft means "Addresses in the specified family cannot be used with this socket" so I am completely at a lost on what to do from here.
You didn't set sin_family so it's set to AF_UNSPEC (since you 0-initialized sa). Before connecting, try:
sa.sin_family = AF_INET;
Based from the answers I got from this thread, I've created this:
//Server
sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/
timeout = 50000;
serv_sock_input[0] = TCP(1234);
serv_sock_input[1] = UDP(9876);
input_protocols[0] = "tcp";
input_protocols[1] = "udp";
while (1)
{
FD_ZERO(&sock_set);
for (x = 0; x<number_of_inputs; x++)
{
FD_SET(serv_sock_input[x], &sock_set);
}
select_timeout.tv_sec = timeout;
select_timeout.tv_usec = 0;
if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
printf("No requests");
else
{
for (x = 0; x<number_of_inputs; x++)
{
if (FD_ISSET(serv_sock_input[x],&sock_set))
{
printf("\nRequest on port %d: \n", x);
if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE
{
accept_socket(serv_sock_input[x]);
printf("Input TCP Port %d\n",x);
close_socket(serv_sock_input[x]);
}
else
{
printf("Input UDP Port %d\n",x);
}
}
}
}
}
sock_term();
}
int TCP (unsigned short port)
{
int sock;
struct sockaddr_in servAddr;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
exit(1);
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
exit(1);
if (listen(sock, 5) < 0)
exit(1);
return sock;
}
int UDP (unsigned short port)
{
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for sending/receiving datagrams */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
exit(1);
/* Construct local address structure */
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family */
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
exit(1);
return sock;
}
//Client
sock_init();
if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
exit(1);
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
client_addr.sin_port = htons(1234);
if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0)
exit(1);
closesocket(client_sock_output);
sock_term();
When the server starts, the server gets blocked at the if(select(...)) statement.
So when I run the Server, and then the client, the client connects to the server (sometimes it takes a couple times to run the client before they connect). Then the if(select...)) statement is no longer true and it proceeds to the else.
After that, the client closes the connection, and the program. However, and this is where my problem happens, the if(select(...)) statement is always false. I get this output:
Request on port 0:
Input TCP Port 0
Request on port 1:
Input UDP Port 1
This output repeats forever. How come it doesn't get stuck at the if(select(...))?
You have two problems: you don't understand how accept() works in TCP, and you need to read the incoming data in UDP.
select() tells you that a listening socket has connection to accept, or reading socket has data to read.
For select to stop telling you this, you need to actually read the data or accept the connection.
In your UDP branch, you need to call receiv to actually get the data. If you don't, select will keep telling you that you have data.
In your TCP branch, you call accept_socket. I don't know what is your implementation of it, but it's most probably wrong to close the socket you just called accept() on. accept() returns a new socket for you - the one you should be using for IO. If anything needs to be closed, it's that new socket.
Please check why you have this in server.
if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
replace it with
if (select(maxDescPlus1, &sock_set, NULL, NULL, &select_timeout) == 0)
where maxDescPlus1 --> is number of descriptors to select plus 1 value.