I want to write a multi clients socket program,
but I get Bad file descriptor when the stage of accept.
How can I correct my code? Thanks!
Here is my code
http://codepad.org/q0N1jTgz
Thanks!
Here is my part of code!
while(1)
{
struct sockaddr_in client_addr;
int addrlen = sizeof(client_addr);
/*Accept*/
if(clientfd = accept(sockfd, (struct sockaddr *)&client_addr, (socklen_t*)&addrlen) < 0)
{
perror("Accpet Error");
close(sockfd);
exit(-1);
}
/*Fork process*/
if(child = fork() < 0)
{
perror("Fork Error");
close(sockfd);
exit(-1);
}
else if(child == 0)
{
int my_client = clientfd;
close(sockfd);
send(my_client, welcome, sizeof(welcome), 0);
while ((res = recv(my_client, buffer1, sizeof(buffer1), 0)) > 0)
{
string command(buffer1);
cout << "receive from client:" << command << ", " << res << " bytes\n";
memset(buffer1, '\0', sizeof(buffer1));
}
}
close(clientfd);
}
there are a few bugs in your code
first you need to use parentheses around the assignments for child and clientfd.
line 68 should be changed to
if((clientfd = accept(sockfd, (struct sockaddr *)&client_addr, (socklen_t*)&addrlen)) < 0)
and line 76 should be
if((child = fork()) < 0)
additionally you must return or exit() from the forked process since you have already closed the listening socket.
so add exit(0); or return 0; after line 94
I highly recommend you compile your code with warnings enabled, to catch the assignment problems early. e.g use the -Wall and -Wextra flags if you are using gcc or g++
Related
I'm new to networking and trying to create a simple client, server socket program in C, where arguments determine whether the program should run as a client or server. I did this by using simple if statements (if a flag is given, run as server, else run as client), but I'm not sure how to test this. I run my code with the argument to be a server in one terminal (on localhost and port number 3000 for example), and open another terminal and run the code with the argument to be a client (also on localhost and the same port).
The expected result is to see the client prompt the user for a message (if connected successfully), and send that message to the server, which prints out the message, however, I don't get the prompt on the client terminal to enter a message.
(I got the code for server and client behavior from one of many websites online, but they separate the client.c and server.c, whereas I want to combine both into one .c program)
Here's my code below, the error is triggered by
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
in the client section of the code.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n, i, server = 0; // 1 = server, 0 = client
// check if server or client
for (i = 0; i<argc; i++) {
if (strcmp(argv[i], "-l") == 0)
server = 1;
}
// client
if (server == 0) {
struct hostent *server;
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"FOUR*** ERROR, no such host\n");
exit(0);
}
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(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
return 0;
}
// server
if (server == 1) {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
return 0;
}
}
Here's the exact error output:
In one terminal window, I run the program as a server first:
$ ./socketz -l localhost 2003
Then in another terminal window, I run the program as a client:
$ ./socketz localhost 2003
ERROR connecting: Connection refused
The reason you can't connect is because your server process is not listening on port 2003. In particular, on this line:
serv_addr.sin_port = htons(portno);
The value of portno is zero, which causes the value of serv_addr.sin_port to also be zero, which accept() interprets as meaning that it should just pick an available TCP port to bind to.
The root of the problem is here:
portno = atoi(argv[1]);
... that line assigns a value to portno based on the first argument you entered when running the program, but you entered this:
./a.out -l localhost 2003
So the first argument is "-l", which is a non-number so it will cause atoi() to return 0. I think what you intended was portno = atoi(argv[3]); instead.
I am developing client-server application which transfers data via UDP.
I am facing the problem of dropped packets. I added socket buffer checking to detect potential overflow. Also my app checks sequence of received numbers in packets. Packets have fixed size. If free space of socket buffer is less than threshold (size of 3 packets for example) then "Critical level of buffer" message is logged. If number of packet is skipped in sequence then corresponding message is logged. There is code:
UdpServer::UdpServer(asio::io_service& io, uint16_t port, uint32_t packetSize) : CommunicationBase(io, port),
m_socket(io, asio::ip::udp::endpoint(asio::ip::address_v6::any(), m_port))
{
m_buffer = new uint8_t[packetSize];
m_packetSize = packetSize;
m_socketBufferSize = m_packetSize * 32;
m_criticalLevel = 5 * m_packetSize;
asio::ip::udp::socket::receive_buffer_size recieveBuffSize(m_socketBufferSize);
m_socket.set_option(recieveBuffSize);
}
UdpServer::~UdpServer()
{
std::free(m_buffer);
}
void UdpServer::StartReceive(std::function<void(uint8_t* buffer, uint32_t bytesCount)> receiveHandler)
{
m_onReceive = receiveHandler;
Receive();
}
inline void UdpServer::Receive()
{
m_socket.async_receive(asio::null_buffers(), [=](const boost::system::error_code& error, size_t bytesCount)
{
OnReceive(bytesCount, error);
});
}
void UdpServer::OnReceive(size_t bytesCount, const boost::system::error_code& error)
{
static uint16_t lastSendNum = 65535;
uint16_t currentNum = 0;
uint16_t diff = 0;
if (error)
{
if (error == asio::error::operation_aborted)
{
logtrace << "UDP socket reports operation aborted, terminating";
return;
}
logerror << "UDP socket error (ignoring): " << error.message();
}
else
{
asio::ip::udp::endpoint from;
boost::system::error_code receiveError;
size_t bytesRead = 0;
size_t bytesAvailable = m_socket.available();
while (bytesAvailable > 0)
{
if (m_socketBufferSize - bytesAvailable < m_criticalLevel)
{
logwarning << "Critical buffer level!";
}
bytesRead = m_socket.receive(asio::buffer(m_buffer, m_packetSize), 0, receiveError);
if (receiveError)
{
logerror << "UDP socket error: " << receiveError.message();
break;
}
currentNum = *reinterpret_cast<uint16_t*>(m_buffer);
diff = currentNum - lastSendNum;
if (diff != 1)
{
logdebug << "Chunk skipped: " << diff << ". Last " << lastSendNum << " next " << currentNum;
}
lastSendNum = currentNum;
if (m_onReceive)
{
m_onReceive(m_buffer, bytesRead);
}
bytesAvailable = m_socket.available();
}
}
Receive();
}
Even if checking of buffer status and packet processing m_onReceive are disabled and bytesAvailable > 0 replaced with true, udp packets are dropped. Speed rate is ~71 Mb/s via 1Gb Ethernet.
Windows 10 is used. Also I checked netstat -s result: no reassembly failures. Socket buffer is never being overflowed.
Quoting form this online kernel doc
SO_TIMESTAMPING
Generates timestamps on reception, transmission or both. Supports
multiple timestamp sources, including hardware. Supports generating
timestamps for stream sockets.
Linux supports TCP timestamping, and I tried to write some demo code to get any timestamp for TCP packet.
The server code as below:
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
int c = sizeof(struct sockaddr_in);
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
// Note: I am trying to get software timestamp only here..
int oval = SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE;
int olen = sizeof( oval );
if ( setsockopt( client_sock, SOL_SOCKET, SO_TIMESTAMPING, &oval, olen ) < 0 )
{ perror( "setsockopt TIMESTAMP"); exit(1); }
puts("Connection accepted");
char buf[] = "----------------------------------------";
int len = strlen( buf );
struct iovec myiov[1] = { {buf, len } };
unsigned char cbuf[ 40 ] = { 0 };
int clen = sizeof( cbuf );
struct msghdr mymsghdr = { 0 };
mymsghdr.msg_name = NULL;
mymsghdr.msg_namelen = 0;
mymsghdr.msg_iov = myiov;
mymsghdr.msg_iovlen = 1;
mymsghdr.msg_control = cbuf;
mymsghdr.msg_controllen = clen;
mymsghdr.msg_flags = 0;
int read_size = recvmsg( client_sock, &mymsghdr, 0);
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
else
{
struct msghdr *msgp = &mymsghdr;
printf("msg received: %s \n",(char*)msgp->msg_iov[0].iov_base);// This line is successfully hit.
// Additional info: print msgp->msg_controllen inside gdb is 0.
struct cmsghdr *cmsg;
for ( cmsg = CMSG_FIRSTHDR( msgp );
cmsg != NULL;
cmsg = CMSG_NXTHDR( msgp, cmsg ) )
{
printf("Time GOT!\n"); // <-- This line is not hit.
if (( cmsg->cmsg_level == SOL_SOCKET )
&&( cmsg->cmsg_type == SO_TIMESTAMPING ))
printf("TIME GOT2\n");// <-- of course , this line is not hit
}
}
Any ideas why no timestamping is available here ? Thanks
Solution
I am able to get the software timestamp along with hardware timestamp using onload with solarflare NIC.
Still no idea how to get software timestamp alone.
The link you gave, in the comments at the end, says:
I've discovered why it doesn't work. SIOCGSTAMP only works for UDP
packets or RAW sockets, but does not work for TCP. – Gio Mar 17 '16 at 9:331
it doesn't make sense to ask for timestamps for TCP, because there's
no direct correlation between arriving packets and data becoming
available. If you really want timestamps for TCP you'll have to use
RAW sockets and implement your own TCP stack (or use a userspace TCP
library). – ecatmur Jul 4 '16 at 10:39
Im trying to use memory map I/O netlink to transfer bulk packets from kernel to user space, and I followed a guide document from Patrick McHardy 1. However, when I try to setup the shared ring buffer in user space by using:
setsockopt(sock_fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req));
setsockopt(sock_fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req));
Both functions return -1, and the errno is 1, which means the descriptor is invalid. Im confused about that because I also referred to many other source codes and they can setup the ring successfully.
My code is almost the same as Patrick's 1:
int sock_fd = -1;
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_DECODE);
if (sock_fd < 0)
return -1;
bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
/* init the mmap buffer */
unsigned int block_size = 16 * getpagesize();
struct nl_mmap_req req = {
.nm_block_size = block_size,
.nm_block_nr = 64,
.nm_frame_size = 16384,
.nm_frame_nr = 64 * block_size / 16384,
};
/* Configure ring parameters */
if (setsockopt(sock_fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0){
if(errno > 0)
printf("%d\n", errno);
}
if (setsockopt(sock_fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0){
if(errno > 0)
printf("%d", errno);
exit(1);
}
This code is built in Ubuntu 14.04, and kernel version is 3.13.0-74-generic.
Anyone idea about it? Thanks a lot.
I have a program which goes this way.
{
memset(&hints, 0, sizeof(struct addrinfo));
/* fill the hints struct */
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
//hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
//hints.ai_protocol = IPPROTO_UDP;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
if(iFamily == AF_INET)
hints.ai_family = AF_INET;
else if(iFamily == AF_INET6)
hints.ai_family = AF_INET6;
/* Code for getting gettaddressinfo */
if(iFamily == AF_INET)
{
iRet = bind(SockIPC, res->ai_addr, sizeof(struct sockaddr_in));
char sBuff[1024];
sprintf(sBuff, "errno [%d] ", errno);
fp=fopen("debug.log","a+");
fprintf(fp,"IPv4 bind error\n ");
fprintf(fp,"bind error = %s\n",sBuff);
fclose(fp);
fflush(stdout);
}
}
In the above piece of code I am trying to bind a UDP socket created.
I am getting the following bind error
bind error = 266
Which is address already in use.
Can anyone
let me know where I am going wrong.
There's no evidence of a problem here. It's only valid to evaluate errno if the immediately prior system call has returned -1, and perror("bind"); would have been a lot simpler:
if (bind(...) == -1)
{
perror("bind");
}
else // continue with execution
However there almost certainly was an error, if not 266: EADDRINUSE is 98, not 266. SOCK_STREAM and IPPROTO_UDP don't go together. You need SOCK_DGRAM and IPPROTO_UDP.