I am writing an UDP client/server programs in C on linux. The thing is that I must add connection check feature. in linux man pages i found example of udp client with this feature( http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo.3.html ). It uses write/read functions to check server response. I tried to apply it to my program, and it looks like this:
char *test = "test";
nlen = strlen(test) + 1;
if (write(sock, test, nlen) != nlen) { // socket with the connection
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(sock, buf, nlen);
if (nread == -1) {
perror("Connection");
exit(EXIT_FAILURE);
}
the problem is than than i execute program with this bit when server is on, it does nothing except reading input infinite time which it doesn't use too. I tried kill(getpid(), SIGHUP) interrupt, which i found other similar topic here, and shutdown(sock, 1), but nothing seems to work. Could you please tell me a way out how to stop the input read or any other possible option to check if udp server is active?
You should use asynchronous reading.
For this you must use the select() function from "sys/socket.h".
The function monitors the socket descriptor for changes without blocking.
You can find the reference for it here or here or by typing "man select" in your console.
There is an example here for Windows, but its usage is very similar to UNIX.
Related
There are some points that i cant understand about select() and i wish your guide. As i read about this function, i've found that
The select() function gives you a way to simultaneously check
multiple sockets to see if they have data waiting to be recv()d, or if
you can send() data to them without blocking, or if some exception has
occurred.
1) The first thing that i understood was that this function can check the sockets in parallel. now imagine the sock1 and sock2 receives packets exactly in the same time (packet1 from sock1 and packet2 from sock2) and there are some process that have to done over each packet. is the processing of packets in the parallel? or the packet1 will process then packet 2 will process? (for example in the following code)
int rv = select(maxSd, &readfds, NULL, NULL, NULL);
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Timeout occurred! No data after 10.5 seconds.\n");
} else {
// one or both of the descriptors have data
if (FD_ISSET(sock1, &readfds)) {
printf("socket %i RECEIVED A PACKET \n", sock1);
recvlen = recvfrom(sock1, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr1, &addrlen1);
if (recvlen > 0) {
buf[recvlen] = 0;
printf("received message: \"%s\" (%d bytes)\n", buf, recvlen);
Packet mp;
mp.de_packet((unsigned char *)buf,recvlen);
}
else {
printf("uh oh - something went wrong!\n");
}
}
if (FD_ISSET(sock2, &readfds)) {
printf("socket %i RECEIVED A PACKET \n", sock2);
recvlen2 = recvfrom(sock2, buf2, BUFSIZE, 0, (struct sockaddr *)&remaddr2, &addrlen2);
if (recvlen2 > 0) {
buf[recvlen2] = 0;
printf("received message2: \"%s\" (%d bytes)\n", buf2, recvlen2);
Packet mp;
mp.de_packet((unsigned char *)buf,recvlen);
}
else
printf("uh oh - something went wrong2!\n");
}
}
2) The other doubt about select that i have is related to blocking and non blocking.
What is exactly the meaning of blocking? Does it mean that the program stops on this line till an event occur?
I think that to avoid blocking it is possible to use timeval tv or fcntl(). Is there any better way too?
Thanks in advance
Upon return of the select, provided it didn't return 0 or -1, your program needs to loop on all elements of readfds and evaluate if ISSET, it is set the corresponding socket must be processed. So, your code is also correct supposing only sock1 and sock2 were set in readfds. The evaluation of the sockets in readfds is usually done sequentially by the same thread. Then the packets in each socket can be processed sequentially or in parallel. It must be clear that two sockets are totally independent of each other, there is no possibility of race condition. All this depends on how you program it. For example for each socket that ISSET returns true you can spawn a thread that processes it or you can pass it to a work queue for a set of worker threads to process each one in parallel. There is no limitation of any kind. You could even check readfs in parallel, for example you could have a thread checking the lower half of the set and another thread checking the upper half. This is just an example. Again, there is no limitation providing you program it well without generating any race conditions in your application.
Regarding the concept of blocking or non-blocking, select will always block until a socket in the sets has an event to process (read, write, exception) or there is a timeout (if you set the timeout value).
You could also be talking about blocking and non-blocking sockets, which is different. Blocking sockets are those that can be blocked in a read or write operation. A blocking socket will block in a read operation until there is a Byte ready to be read and it will block in a write operation if the send buffer is full and it cannot write the bytes in the buffer (this may happen in STREAM sockets). It will block until it can write its Bytes. A non-blocking socket will not block in a read operation if there is nothing to read, function read will return -1 and errno will be set to EAGAIN or EWOULDBLOCK (see: http://man7.org/linux/man-pages/man2/read.2.html).
select is usually used with non-blocking sockets so that a thread just blocks there until there is a socket ready to be processed. This is good because otherwise your application would need to be polling the non-blocking sockets all the time, which is not efficient.
select will handle all you sockets in parallel but just to check if there is any event. select does not process any packet, if you pay attention to your example, after select returns your application will read the data from the sockets and this can be done sequentially or in parallel.
I hope this explanation helps you understand the concept.
I have been trying to write a working program that takes in data from a UDP socket and displays it in an edit control box as you receive the data (My exposure to c++ is also only about a week :P have only done embedded C code before). I have a working program that can send and output data on a button click but I want something that can do it in real time. The aim is scale this up into a larger GUI program that can send control data to hardware and get responses from them.
I have run into various problems including:
The program just not executing my OnReceivefunction (derived from
CAsyncSocket)
Getting the OnReceive function to run on a separate thread so that it can still run after a button has been clicked sending a control packet to the client then waiting for a response in a while loop
Not being able to output the data in the edit box (tried using both CEdit and CString)
ReplaceSel error saying that the type char is incompatible with LPCTSTR
My code is based on this codeproject.com tutorial, being almost exactly what I want but I get the error in 4.
EDIT: the error in 4. disappears when I change it to a TCHAR but then it outputs random chinese characters. The codeproject.com tutorial outputs the correct characters regardless of char or TCHAR declaration. When debugged my code has type wchar_t instead type char like the other code.
Chinese output
In the working program echoBuffer[0] the character sent and displayed was a 1
UINT ReceiveData(LPVOID pParam)
{
CTesterDlg *dlg = (CTesterDlg*)pParam;
AfxSocketInit(NULL);
CSocket echoServer;
// Create socket for sending/receiving datagrams
if (echoServer.Create(12345, SOCK_DGRAM, NULL) == 0)
{
AfxMessageBox(_T("Create() failed"));
}
for (;;)
{ // Run forever
// Client address
SOCKADDR_IN echoClntAddr;
// Set the size of the in-out parameter
int clntAddrLen = sizeof(echoClntAddr);
// Buffer for echo string
char echoBuffer[ECHOMAX];
// Block until receive message from a client
int recvMsgSize = echoServer.ReceiveFrom(echoBuffer, ECHOMAX, (SOCKADDR*)&echoClntAddr, &clntAddrLen, 0);
if (recvMsgSize < 0)
{
AfxMessageBox(_T("RecvFrom() failed"));
}
echoBuffer[recvMsgSize] = '\0';
dlg->m_edit.ReplaceSel(echoBuffer);
dlg->m_edit.ReplaceSel(_T("\r\n"));
}
}
After reading the link that #IInspectable provided about working with strings and checking the settings differences between the two programs it became clear that the issue lay with an incorrect conversion to UNICODE. My program does not require it so I disabled it.
This has cleared up the issue in 4. and provided solutions for 2 and 3.
I also think I know why another instance of my program would not run OnReceivein 1. because that file was not being defined by one that was already being run by the program, but that is now irrelevant.
I'm having a client process launch a server process with xinetd. As I understand it, the server come to life being able to read from the client via its STDIN, and write to the client via its STDOUT. For various reasons (mainly having the server be able to use select() and then read() or recv() ) I want to be able to somehow transform STDIN and STDOUT into a socket and then perform ordinary socket I/O on it, as I will with the other servers that my server will connect to.
Can this be done? Is this even a meaningful question?
All the function calls you mention can be used on the file descriptors with the numbers STDIN_FILENO and STDOUT_FILENO (from <unistd.h>). So I would venture you dont need any transformation.
EDIT: A bit unorthodox, but have you tried writing on STDOUT_FILE or reading STDIN_FILENO in your server? By very quickly glancing at the xinetd code, it looks like it just dup()s the open socket fd to all fds of the server. Maybe you can use either one as full duplex.
I only looked here
for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ )
{
if ( dup2( descriptor, fd ) == -1 )
{
msg_resume();
msg( LOG_ERR, func,
"dup2( %d, %d ) failed: %m", descriptor, fd ) ;
_exit( 1 ) ;
}
}
I'm trying to write into an EEPROM via I²C from user space. I'm using the /dev device file and the open, read, write and ioctl functions. Reading works without a problem, but when I use the same code for writing (just replacing read with write), it fails. The EEPROM is not write protected (echoing into the device file of the EEPROM driver works).
The code I have is as follows.
if ((fd = open(write_destination, O_RDWR)) < 0) {
goto error;
}
if (ioctl(fd, I2C_SLAVE_FORCE, 0x50) < 0) {
goto error_fd;
}
while((n = write(fd, self->fields[i].buf, self->fields[i].size)) != self->fields[i].size)
perror("");
What am I overlooking?
Some EEPROMs only allow writing small amounts, then wait, and then write more. Check the datasheet to be sure. Also, I recommend to use a logic analyzer to check the correct commands are going to the I²C - I love the analyzer at www.salae.com.
I have an intermittent problem with a telnet based server on Unix (the problem crops up on both AIX and Linux).
The server opens two sockets, one to a client telnet session, and one to a program running on the same machine as the server. The idea is that the data is passed through the server to and from this program.
The current setup has a loop using select to wait for a "read" file descriptor to become available, then uses select to wait for a "write" file descriptor to become available.
Then the program reads from the incoming file descriptor, then processes the data before writing to the outgoing descriptor.
The snippet below shows what is going on. The problem is that very occasionally the read fails, with errno being set to ECONNRESET or ETIMEDOUT. Neither of these are codes documented by read, so where are they coming from?
The real question is, how can I either stop this happening, or handle it gracefully?
Could doing two selects in a row be the problem?
The current handling behaviour is to shut down and restart. One point to note is that once this happens it normally happens three or four times, then clears up. The system load doesn't really seem to be that high (it's a big server).
if (select(8, &readset, NULL, NULL, NULL) < 0)
{
break;
}
if (select(8, NULL, &writeset, NULL, NULL) < 0)
{
break;
}
if (FD_ISSET(STDIN_FILENO, &readset)
&& FD_ISSET(fdout, &writeset))
{
if ((nread = read(STDIN_FILENO, buff, BUFFSIZE)) < 0)
{
/* This sometimes fails with errno =
ECONNRESET or ETIMEDOUT */
break;
}
}
Look at the comments in http://lxr.free-electrons.com/source/arch/mips/include/asm/errno.h on lines 85 and 98: these basically say there was a network connection reset or time out. Check and see if there are timeouts you can adjust on the remote network program, or send some periodic filler bytes to ensure that the connection stays awake consistently. You may just be victim of an error in the network transit path between the remote client and your local server (this happens to me when my DSL line hiccups).
EDIT: not sure what the downvote is for. The man page for read explicitly says:
Other errors may occur, depending on the object connected to fd.
The error is probably occuring in the select, not in the read: you're not checking errors after the select, you're just proceeding to the read, which will fail if the select returned an error. I'm betting if you check the errno value after the select call you'll see the errors: you don't need to wait for the read to see the errors.