When i am connecting to an IRC server via telnet everything works fine, but in my program there is no respond from server after the greeting message. What's wrong?
PS when i am sending "JOIN #channel" server responds.
fragment of the code:
while (true)
{
ret = recv(pocket, buf, 512, 0);
if (ret == 0 || ret == SOCKET_ERROR)
{
printf("Serwer przerwal polaczenie");
break;
}
buf[ret] = '\0';
input = buf;
printf("%s\n", input.c_str());
if (fTime)
{
isend(pocket, "USER foox 0 0 :foox");
isend(pocket, "NICK foobar");
fTime = false;
}
memset(buf, 0, sizeof(buf));
}
isend function:
bool isend(SOCKET socket,std::string message)
{
int ret = send(socket, message.c_str(), message.size() + 1, 0);
if (!ret){
printf("Nie udalo sie wyslac pakietu: \"%s\"", message);
return false;
}
else
return true;
}
Don't read upon connection. Send the NICK and USER information as per RFC 2812. You're doing it in reverse order that is suggested. Both NICK and USER lines need to be correctly terminated with \r\n and then you can read.
Don't send message.size()+1 - do send message.size(). I don't understand why you were sending message.size()+1 and you didn't answer why in my comments.
If you get stuck I suggest using something like Wireshark with an unencrypted connection and log how IRC clients manage it.
You have three issues:
You do a blocking read, which will wait forever if there's nothing to read.
You need to send a carriage return and newline after each line.
You don't want to send the terminating zero byte.
Related
I am trying to send GET request to nodejs server from a C++ client.
nodejs server:
const server = http.createServer((request, response) => {
console.log(request.url);
response.end("received");
})
and here is my C++ clients:
while(getline(cin, random_input)) {
int s_len;
input = "GET / HTTP/1.1\r\n\r\n";
s_len = send(sock, input.c_str(), input.size(), 0);
if( s_len < 0)
{
perror("Send failed : ");
return false;
}
cout<<socket_c.receive(1024);
}
string tcp_client::receive(int size=512)
{
char buffer[size];
string reply;
int r_len; // received len
//Receive a reply from the server
r_len = recv(sock, buffer, sizeof(buffer), 0);
if( r_len < 0)
{
puts("recv failed");
}
if(buffer[r_len-1] == '\n') {
buffer[r_len-1] = '\0';
} else {
buffer[r_len] = '\0';
}
reply = buffer;
return reply;
}
so the C++ client can send GET requests each time when it's typing something in the terminal.
It works pretty fine if I type something right after the connection has been established. However, if I wait for 15-30 seconds after establish the connection, then type something on the client program, although the number of byte s_len that has been sent is correct, the server could't received anything.
May I know what goes wrong?
A few errors I spotted:
send return value is not checked correctly. Condition input.size() == s_len must be true.
recv return value is not checked of EOF. It treats r_len of 0 as valid data instead of disconnect. This may be the reason you do not see server replies: it may have disconnected but you did not notice that.
Setting the value of keepAliveTimeout of the node.js server to 0 could solve the problem
I am trying to check if a client has send some new data. This actually tells me that i always have new data:
bool ClientHandle::hasData()
{
fd_set temp;
FD_ZERO(&temp);
FD_SET(m_sock, &temp);
//setup the timeout to 1000ms
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000;
//temp.fd_count possible?
if (select(m_sock+1, &temp, nullptr, nullptr, &tv) == -1)
{
return false;
}
if (FD_ISSET(m_sock, &temp))
return true;
return false;
}
I am connecting with a java client and send a "connection" message which i read inside of the ctor:
ClientHandle::ClientHandle(SOCKET s) : m_sock(s)
{
while (!hasData())
{
}
char buffer[5];
recv(m_sock, buffer, 4, NULL);
auto i = atoi(buffer);
LOG_INFO << "Byte to receive: " << i;
auto dataBuffer = new char[i + 1]{'\0'};
recv(m_sock, dataBuffer, i, NULL);
LOG_INFO << dataBuffer;
//clean up
delete[] dataBuffer;
}
This seems to work right. After that i keep checking if there is new data which always is true even if the java client does not send any new data.
Here is the java client. Don't judge me it's just for checking the connections. It wont stay like this to send the size information as char[].
public static void main(String[] args) throws UnknownHostException,
IOException {
Socket soc = null;
soc = new Socket("localhost", 6060);
PrintWriter out = new PrintWriter(soc.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
soc.getInputStream()));
if (soc != null)
System.out.println("Connected");
out.write("10\0");
out.flush();
out.write("newCon\0");
out.flush();
out.close();
in.close();
soc.close();
}
So what is wrong with the hasData FD_ISSET method?
So what is wrong with the hasData FD_ISSET method?
Actually no. There is a problem with your use of recv().
recv() will return 0 if the client is disconnected and will return this until you close the socket (server-side). You can find this information in the manual.
Even if recv() returns 0, it will "trigger" select().
Knowing that, it's easy to find out the problem: you never check the return value of recv() and so you're unable to say if the client is still connected or not. However, you still add it with FD_SET!
#include <sys/types.h> // for ssize_t
#include <stdio.h> // for perror()
ClientHandle::ClientHandle(SOCKET s) : m_sock(s)
{
while (!hasData())
{
}
char buffer[5];
ssize_t ret = recv(m_sock, buffer, 4, NULL);
if (ret == -1) // error
{
perror("recv");
return ;
}
else if (ret == 0) // m_sock disconnects
{
close(m_sock);
// DO NOT FD_SET m_sock since the socket is now closed
}
else
{
auto i = atoi(buffer);
LOG_INFO << "Byte to receive: " << i;
auto dataBuffer = new char[i + 1]{'\0'};
recv(m_sock, dataBuffer, i, NULL);
LOG_INFO << dataBuffer;
//clean up
delete[] dataBuffer;
}
}
From Steven's book UNIX Networking Programming:
A socket is ready for reading if any of the following four conditions is true:
The number of bytes of data in the socket receive buffer is greater than or equal to the current size of the low-water mark for the socket receive buffer. A read operation on the socket will not block and will return a value greater than 0 (i.e., the data that is ready to be read). We can set this low-water mark using the SO_RCVLOWAT socket option. It defaults to 1 for TCP and UDP sockets.
The read half of the connection is closed (i.e., a TCP connection that has received a FIN). A read operation on the socket will not block and will return 0 (i.e., EOF).
The socket is a listening socket and the number of completed connections is nonzero. An accept on the listening socket will normally not block, although we will describe a timing condition in Section 16.6 under which the accept can block.
A socket error is pending. A read operation on the socket will not block and will return an error (–1) with errno set to the specific error condition. These pending errors can also be fetched and cleared by calling getsockopt and specifying the SO_ERROR socket option.
ISSET is going to return true in all the cases above. After your Java client closes the connection, the socket will be ready for reading in the server.
In ClientHandle::ClientHandle you are not checking the return value of recv and if any data is returned.
Is it blocking in the second call to recv?
You don't check the return value of recv and you don't handle receiving fewer bytes than you asked for. So what do you expect to happen when the connection is closed?
I am new to C++ and socket programming. I studied with Beej's guide so my codes are almost same as the guide, but I am struggling really strange bugs.
First, my server's recv() returns 0. According to document, the client should gracefully close the connection for recv() to return 0. Not really in my case. It returns 0, at the same time, I still receive the data from the client. So, the way Beej's do to receive, does not work for me. Can someone explain how this can be possible?
char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
buf[numbytes] = '\0';
the last line here, because numbytes is 0, it sweeps out all message I received. So I had to comment that out. Now, my code looks like this
char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
//buf[numbytes] = '\0';
printf("received: %s\n", buf);
It now works with receiving some messages sent by client. However, I did some string manipulation (appending) in the client side, and then sent the message. Now, I send string length of 29 in the client side, but the server receives 41 bytes with strange characters.
What I sent: received: Login#1 Mary 123456 451912345
received: Login#1 Mary 123456 451912345ÿ>É„ÿy#ÿ>Ád
Here is how I receive in the server:
while(1) { // main accept() loop
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
char buf[MAXDATASIZE];
int numbytes;
if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1)
perror("recv");
//buf[numbytes] = '\0'; // this had to be commented out
printf("received: %s\n", buf); // prints out with weird characters
string msgRcved = buf;
close(new_fd);
}
This is how I send from client:
// string loginCredential is loaded with "1 Mary 123456 451912345" at this point
loginCredentials.insert(0, "Login#");
const char* msgToSend = loginCredentials.c_str();
int numbytesSent;
if (numbytesSent = send(sockfd, msgToSend, strlen(msgToSend), 0) == -1)
perror("send");
I'd like to know how my recv receives data while it returns 0 at the first place. And, I'd like to know what I am doing wrong to recv data from client/send data to server.
You have a precedence problem.
This:
if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1)
is equivalent to
if (numbytes = (recv(new_fd, buf, MAXDATASIZE-1, 0) == -1))
and
recv(new_fd, buf, MAXDATASIZE-1, 0) == -1
is 0 whenever recv succeeds.
The same problem is present on the sending end.
There's no reason to write such awkward and error-prone condition.
This is safer:
int numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
if (numbytes == -1)
perror("recv");
You have to test 'numbytes' for zero, separately, and if you get it close the socket and exit the read loop, because the peer has closed the connection. Otherwise, and assuming you have also tested for -1, you have to only process 'numbytes' bytes of the buffer. Not all of them. Otherwise you're liable to reprocess bytes you already processed. In this case that might mean restoring the line that null-terminated the buffer, or it might mean this:
printf("%.*s", numbytes, buf);
You are printing whatever garbage was in that stack-allocated buffer, not what the client sent. When recv(2) returns zero, nothing has been placed into the supplied buffer, so this is probably from some previous iteration of the loop.
Notes:
Connected TCP socket is is a bi-directional stream of bytes. This means you might send several of your "messages" and receive them in one chunk on the other side, or the other way around. Read from the socket in a loop until you have enough data to process, i.e. use explicit message separators, or pre-pend a length of your message that follows. This is your application-level protocol.
Don't mix C and C++ string handing like this. std::string has a size() method, use it instead of doing strlen( msgToSend.c_str() ).
Allocating any sizable buffers on the stack, especially ones receiving input from the network is a bad idea.
Printing, or otherwise passing further, unverified network input is a gross security violation leading to all sorts of problems.
Edit 0:
#molbdnilo's answer is the right one. I did not spot the precedence problem in the conditionals. My notes still apply though.
A am writing a client-server program in C. It sends a directory name and receives a list of files as answer. The problem I have is that it gets stuck in an infinite loop.
If I send only one directory name it works, but if I send a list of directories it never ends and outputs nothing.
Server
while(recv(sock, name, BUFSIZE, 0) > 0){
if ((fddir=opendir(name)) == NULL){
send(sock, strerror(errno), strlen(strerror(errno)), 0);
close(sock);
return 1;
}
send(sock, name, strlen(name), 0);
send(sock, ":", strlen(":"), 0);
send(sock, "\n", strlen("\n"), 0);
while ((dirbuf = readdir(fddir)) != NULL){
buf[0] = '\0';
strcat(buf, dirbuf->d_name);
strcat(buf, "\t");
send(sock, buf, BUFSIZE, 0);
}
}
Client
for (int i=1;i<3;i++){
send(sock, argv[i], strlen(path), 0);
while(recv(sock, buf, BUFSIZE, 0) > 0)
printf("%s", buf);
}
The server waits until all directory names are received, and then the client wait until server send all files in it. How do I trace where the program gets stuck?
TCP is not message based, so you have no way of knowing where the boundaries between two client send() calls is when you call recv() on the server. Thus when you send multiple names back-to-back it is possible for the server to receive them all in a single recv() (or however many bytes you allocated for BUFSIZE). This is probably mangling your directory names, causing opendir to fail. This would be more obvious to you if you were checking for errors from send and recv and Captain Obvlious describes in another answer.
You need to check the calls to recv for errors. It returns 0 if the connection was disconnected and -1 on an error. You are only checking for values > 0 which will not work. The example below shows how to approach checking the errors.
while(true)
{
const int result = recv(sock, buf, BUFSIZE, 0);l
if(result == -1)
{
std::cout << "Error: " << errno << std::endl;
break;
}
else if(result == 0)
{
std::cout << "Disconnected" << std::endl;
break;
}
// process the data here. No errors
}
You should also be checking the value returned by send as it works in the same way.
I am trying to use non-blocking TCP sockets. The problem is that they are still blocking. The code is below -
server code -
struct sockaddr name;
char buf[80];
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
int main(int agrc, char** argv) {
int sock, new_sd, adrlen; //sock is this socket, new_sd is connection socket
name.sa_family = AF_UNIX;
strcpy(name.sa_data, "127.0.0.1");
adrlen = strlen(name.sa_data) + sizeof(name.sa_family);
//make socket
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("\nBind error %m", errno);
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, &name, adrlen) < 0)
printf("\nBind error %m", errno);
//listen
if(listen(sock, 5) < 0)
printf("\nListen error %m", errno);
//accept
new_sd = accept(sock, &name, (socklen_t*)&adrlen);
if( new_sd < 0) {
cout<<"\nserver accept failure "<<errno;
exit(1);
}
//set nonblock
set_nonblock(new_sd);
char* in = new char[80];
std::string out = "Got it";
int numSent;
int numRead;
while( !(in[0] == 'q' && in[1] == 'u' && in[2] == 'i' && in[3] == 't') ) {
//clear in buffer
for(int i=0;i<80;i++)
in[i] = ' ';
cin>>out;
cin.get();
//if we typed something, send it
if(strlen(out.c_str()) > 0) {
numSent = send(new_sd, out.c_str(), strlen(out.c_str()), 0);
cout<<"\n"<<numSent<<" bytes sent";
}
numRead = recv(new_sd, in, 80, 0);
if(numRead > 0)
cout<<"\nData read from client - "<<in;
} //end while
cout<<"\nExiting normally\n";
return 0;
}
client code -
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
int main(int agrc, char** argv) {
int sock, new_sd, adrlen;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//stuff for server socket
name.sa_family = AF_UNIX;
strcpy(name.sa_data, "127.0.0.1");
adrlen = strlen(name.sa_data) + sizeof(name.sa_family);
if(connect(sock, &name, adrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection\n";
//set nonblock
set_nonblock(sock);
std::string out;
char* in = new char[80];
int numRead;
int numSent;
while(out.compare("quit")) {
//clear in
for(int i=0;i<80;i++)
in[i] = '\0';
numRead = recv(sock, in, 80, 0);
if(numRead > 0)
cout<<"\nData read from server - "<<in;
cout<<"\n";
out.clear();
cin>>out;
cin.get();
//if we typed something, send it
if(strlen(out.c_str())) {
numSent = send(sock, out.c_str(), strlen(out.c_str()), 0);
cout<<"\n"<<numSent<<" bytes sent";
}
} //end while
cout<<"\nExiting normally\n";
return 0;
}
Whenever I run it, the server still waits for me to send something before it will read and output what the client has sent. I want either the server or client to be able to send the message as soon as I type it, and have the other read and output the message at that time. I thought non-blocking sockets was the answer, but maybe I am just doing something wrong?
Also, I was using a file instead of my 127.0.0.1 address as the sockaddr's data. If that is not how it should be properly used, feel free to say so (it worked how it worked previously with a file so I just kept it like that).
Any help is appreciated.
General approach for a TCP server where you want to handle many connections at the same time:
make listening socket non-blocking
add it to select(2) or poll(2) read event set
enter select(2)/poll(2) loop
on wakeup check if it's the listening socket, then
accept(2)
check for failure (the client might've dropped the connection attempt by now)
make newly created client socket non-blocking, add it to the polling event set
else, if it's one of the client sockets
consume input, process it
watch out for EAGAIN error code - it's not really an error, but indication that there's no input now
if read zero bytes - client closed connection, close(2) client socket, remove it from event set
re-init event set (omitting this is a common error with select(2))
repeat the loop
Client side is a little simpler since you only have one socket. Advanced applications like web browsers that handle many connections often do non-blocking connect(2) though.
Whenever I run it, the server still waits for me to send something before it will read and output what the client has sent.
Well, that is how you wrote it. You block on IO from stdin, and then and only then do you send/receive.
cin>>out;
cin.get();
Also, you are using a local socket (AF_UNIX) which creates a special file in your filesystem for interprocess communication - this is a different mechanism than IP, and is definitely not TCP as you indicate in your question. I suppose you could name the file 127.0.0.1, but that really doesn't make sense and implies confusion on your part, because that is an IP loopback address. You'll want to use AF_INET for IP.
For an excellent starter guide on unix networking, I'd recommend http://beej.us/guide/bgnet/
If you want the display of messages received to be independant of your cin statements, either fork() off a seperate process to handle your network IO, or use a separate thread.
You might be interested in select(). In my opinion non-blocking sockets are usually a hack, and proper usage of select() or poll() is generally much better design and more flexible (and more portable). try
man select_tut
for more information.
I think you have to set non-block sooner (ie get the socket then set it non block)
also check that the fcntl to set it actually worked
If you want non-blocking i/o, you want to use select. You can set it with stdin as one of the sockets it is listening on, along with the client sockets (just add file descriptor 1, which is stdin, to the fd_set).
http://beej.us/guide/bgnet/output/html/multipage/advanced.html
I would recommend reading through what beej has to say about select. It looks a little intimidating but is really useful and simple to use if you take a little time to wrap your head around it.