I'm trying to communicate with several Modbus RTU devices through one usb to RS232 to RS485 port at baudrate 38400, 1 start bit, 8databits, no parity and 1 stop bit.
Communication processes with one Modbus RTU device is as follows:
Send 8 bytes to the device;
wait for replies from the device;
Receive 23 bytes of replies.
According to my calculation and the digital oscilloscope, send 8 bytes costs 2.083ms, receive 23 bytes costs 5.99ms, response time of the Modbus RTU device is about 1.3ms. So time of the communication process costs 9.373ms in total.
But in my test program I found the average communication time is about 15ms (10000 times average). I wonder where does the additional 5 more milliseconds come from and how could I optimize my program to reduce this time.
Thanks in advance!
The test program is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
void print_hex_buf(unsigned char *buffer, int size)
{
for (int i=0; i<size; i++)
{
printf("%02x ", buffer[i]);
}
printf("\n");
}
void diff_time(struct timeval t1, struct timeval t2, struct timeval *diff)
{
time_t sec;
suseconds_t usec;
//time in two different days
if (t1.tv_sec > t2.tv_sec)
sec = t2.tv_sec + 24*60*60 - t1.tv_sec;
else
sec = t2.tv_sec - t1.tv_sec;
usec = t2.tv_usec - t1.tv_usec;
if (usec < 0)
{
sec -= 1;
usec += 1000000;
}
diff->tv_sec = sec;
diff->tv_usec = usec;
}
int serial_write(int uart_fd, char *buffer, int size)
{
int count = 0;
count = write(uart_fd, buffer, size);
return count;
}
int serial_read(int uart_fd, char *buffer, int size)
{
int count = 0;
int bytes_read = 0;
int read_retry = 0;
fd_set fds_read;
struct timeval timeout;
FD_ZERO(&fds_read);
FD_SET(uart_fd, &fds_read);
timeout.tv_sec = 0;
timeout.tv_usec = 500000; //500ms
int ret = select(uart_fd + 1, &fds_read, NULL, NULL, &timeout);
if (ret > 0 && FD_ISSET(uart_fd, &fds_read))
{
count = read(uart_fd, buffer, size);
bytes_read = (count > 0)?count:0;
while (bytes_read < size && read_retry++ < 500)
{
count = read(uart_fd, buffer+bytes_read, size-bytes_read);
bytes_read += (count > 0)?count:0;
if (bytes_read >= size)
break;
}
}
else
{
printf("Failed to from uart!\n");
return -1;
}
return bytes_read;
}
int main(int argc, char** argv)
{
int fd;
struct termios opt;
int count;
unsigned char send_buf[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x09, 0x30, 0x0c};
unsigned char buffer[256];
int iteration = 0;
int delay_ms = 0;
int err_count = 0;
int cycle = 0;
suseconds_t average_time = 0;
setbuf(stdout, NULL);
if (argc != 3)
{
printf("Usage: testuart [uart device] [iteration]\n");
return 0;
}
iteration = atoi(argv[2]);
fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
printf("Failed to open port: %s\n", argv[1]);
return -1;
}
if (tcgetattr(fd, &opt) != 0)
{
printf("Failed to get uart attribute!\n");
return -1;
}
opt.c_cflag = B38400|CS8|CREAD|CLOCAL;
opt.c_iflag = IGNPAR;
opt.c_cflag &= ~PARENB;
opt.c_cflag &= ~PARODD;
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
opt.c_oflag &= ~OPOST;
opt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &opt) != 0)
{
printf("Failed to setup serial port!\n");
close(fd);
return -1;
}
while (cycle++ < iteration)
{
printf("Send hex command:\n");
print_hex_buf(send_buf, 8);
struct timeval tm_start;
struct timeval tm_end;
struct timeval tm_diff;
gettimeofday(&tm_start, NULL);
count = serial_write(fd, send_buf, 8);
if (count != 8)
{
printf("Failed to write 8 bytes!\n");
close(fd);
return -1;
}
count = serial_read(fd, buffer, 23);
if (count <= 0)
{
printf("serial read returns %d\n", count);
close(fd);
return -1;
}
gettimeofday(&tm_end, NULL);
diff_time(tm_start, tm_end, &tm_diff);
print_hex_buf(buffer, count);
printf("serial communication costs %ld.%06ld seconds.\n",
tm_diff.tv_sec, tm_diff.tv_usec);
average_time = ((average_time*(cycle-1))+tm_diff.tv_usec)/cycle;
}
printf("%d times, average time in usec is %ld\n", cycle-1, average_time);
close(fd);
return 0;
}
Thanks to sawdust!
The following link helps! The average time has reduced from 15ms to 10ms.
High delay in RS232 communication on a PXA270
Related
Trying read calls on disks using read() command on 2 different kind of disks:
ssize_t read(int fd, void *buf, size_t count);
http://man7.org/linux/man-pages/man2/read.2.html
Newly Formatted Disk
Disk where data was inserted and Deleted
Environment:
Disk Size: 500 GB
Disk Type: SSD
OS: Ubuntu 18.04.3
File System: ext4
Avg Read Time for Formatted Disk (in microseconds): 127.11
Avg Read Time for Disk (Data was inserted and deleted) (in microseconds): 514.76
Script for above:
#define _LARGEFILE64_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#define BLOCKSIZE 512
#define TIMEOUT 30
int count;
time_t start;
long total_seek_time = 0, total_read_time = 0;
int unread_complete_block_count = 0;
void done()
{
time_t end;
time(&end);
if (end < start + TIMEOUT)
{
printf(".");
alarm(1);
return;
}
if (count)
{
printf(".\nResults: %d seeks/second, %.2f ms random access time\n",
count / TIMEOUT, 1000.0 * TIMEOUT / count);
printf("Total seek time: %ld, Avg seek time: %.2f\n", total_seek_time, 1.0 * total_seek_time / count);
printf("Total read time: %ld, Avg read time: %.2f\n", total_read_time, 1.0 * total_read_time / count);
printf("Unread Complete Block Count: %d\n", unread_complete_block_count);
}
exit(EXIT_SUCCESS);
}
void handle(const char *string, int error)
{
if (error)
{
perror(string);
exit(EXIT_FAILURE);
}
}
long getMicrotime()
{
struct timeval currentTime;
gettimeofday(¤tTime, NULL);
return currentTime.tv_sec * (int)1e6 + currentTime.tv_usec;
}
int main(int argc, char **argv)
{
char buffer[BLOCKSIZE];
int fd, retval;
unsigned long numblocks;
off64_t offset;
long seek_start, seek_end, read_start, read_end;
int buf_ret_val = setvbuf(stdout, NULL, _IONBF, 0);
if (buf_ret_val == 0)
{
printf("Buffer successfully allocated\n");
}
else
{
printf("Unable to allocate buffer. Error code, %d\n", buf_ret_val);
exit(EXIT_FAILURE);
}
printf("Seeker v2.0, 2007-01-15, "
"http://www.linuxinsight.com/how_fast_is_your_disk.html\n");
if (argc != 2)
{
printf("Usage: seeker <raw disk device>\n");
exit(EXIT_SUCCESS);
}
fd = open(argv[1], O_RDONLY);
printf("File Descriptor: %d\n", fd);
handle("open", fd < 0);
printf("Device size in sectors: %u\n", BLKGETSIZE);
printf("Device size in bytes: %lu\n", BLKGETSIZE64);
retval = ioctl(fd, BLKGETSIZE, &numblocks);
handle("ioctl", retval == -1);
printf("Benchmarking %s [%luMB], wait %d seconds", argv[1], numblocks / 2048, TIMEOUT);
time(&start);
srand(start);
signal(SIGALRM, &done);
alarm(1);
for (;;)
{
offset = (off64_t)numblocks * random() / RAND_MAX;
seek_start = getMicrotime();
retval = lseek64(fd, BLOCKSIZE * offset, SEEK_SET);
seek_end = getMicrotime();
handle("lseek64", retval == (off64_t)-1);
read_start = getMicrotime();
retval = read(fd, buffer, BLOCKSIZE);
read_end = getMicrotime();
handle("read", retval < 0);
long current_seek_time = seek_end - seek_start;
long current_read_time = read_end - read_start;
// printf("Current seek time (us): %ld\n", current_seek_time);
// printf("Current read time (us): %ld\n", current_read_time);
if (retval != BLOCKSIZE)
{
printf("Didn't read complete block");
unread_complete_block_count++;
}
total_seek_time += current_seek_time;
total_read_time += current_read_time;
count++;
}
}
Compile: gcc {name}.c
Run: ./a.out /dev/{sdx}
Need to understand why is it happening?
An empty SSD can "know" it's empty, after TRIM, so it's like reading a sparse file. Data has to go over the SATA bus, but (I think) not necessarily come from flash cells at all.
So yes it matters what you did to the block device. The flash remapping layer inside the SSD is firmware running on a fairly powerful microcontroller with lots of RAM.
I have two programs, a server and a client. The server opens a file, writes data to it, and then send its file descriptor to the client over a unix domain socket. Everything works fine untill I introduce a socat proxy in between.
socat -x -v UNIX-LISTEN:/tmp/unixSockSendFe,mode=775,reuseaddr,fork UNIX-CONNECT:/tmp/unixSockSendFd
Explanation
The server listens on /tmp/unixSockSendFd, socat connects to it(UNIX-CONNECT:/tmp/unixSockSendFd), and creates another Unix domain socket(UNIX-LISTEN:/tmp/unixSockSendFe,mode=775,reuseaddr,fork), on which the client connects. Any communication between the client and server gets relayed through socat, which prints the bytes sent in their binary (-x option), and ascii (-v option) form.
If I don't use socat, and client directly connects to server(on /tmp/unixSockSendFd socket), everything works fine, but when socat is used as a proxy, the client crashes with a segmentation fault.
Server
/*Server code - sendfd.c*/
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
char *socket_path = "/tmp/unixSockSendFd";
char *file="/tmp/abcd.txt" ;/*file whose fd is to be sent*/
int sendfd(int sock, int fd);
int recvfd(int s);
char data[]="sahil\0";
int main(int argc, char *argv[]) {
struct sockaddr_un addr;
char buf[100];
buf[0]='\n';
int fd,rc,confd;
int fd_to_send;
int temp,len;
temp=1;
fd_to_send=open(file,O_TRUNC|O_RDWR|O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO);
if(fd_to_send==-1)
{
perror("file open error");
return -1;
}
if (argc > 1) socket_path=argv[1];
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (*socket_path == '\0') {
*addr.sun_path = '\0';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
} else {
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
}
unlink(socket_path);
if(bind(fd,(struct sockaddr*)&addr,sizeof(addr))==-1){
perror("bind error");
return -1;
}
/*Writing data to file before sending fd*/
len=write(fd_to_send,data,(int)strlen(data));
fsync(fd_to_send);
printf("(len=%d)data written in file(content between ## marks) ##%s##\n",len,data);
listen(fd,1);
for(;;){
confd=accept(fd,NULL,NULL);
if(confd==-1)
{
perror("accept error");
continue;
}
else{
printf("new client connected ... sending fd ... \n");
sendfd(confd,fd_to_send);
close(confd);
}
}
return 0;
}
int sendfd(int sock, int fd)
{
struct msghdr hdr;
struct iovec data;
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char dummy = '*';
data.iov_base = &dummy;
data.iov_len = sizeof(dummy);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_name = NULL;
hdr.msg_namelen = 0;
hdr.msg_iov = &data;
hdr.msg_iovlen = 1;
hdr.msg_flags = 0;
hdr.msg_control = cmsgbuf;
hdr.msg_controllen = CMSG_LEN(sizeof(int));
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int*)CMSG_DATA(cmsg) = fd;
//memcpy((CMSG_DATA(cmsg)), &fd, sizeof(fd)); -- from ivshmem server code - this too works instead of previous line
int n = sendmsg(sock, &hdr, 0);
if(n == -1)
printf("sendmsg() failed: %s (socket fd = %d)\n", strerror(errno), sock);
return n;
}
int recvfd(int s)
{
int n;
int fd;
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
char cms[CMSG_SPACE(sizeof(int))];
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = sizeof cms;
if((n=recvmsg(s, &msg, 0)) < 0)
return -1;
if(n == 0){
perror("unexpected EOF");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
Client
/*Client code - recvfd.c*/
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
char *socket_path = "/tmp/unixSockSendFe";
int sendfd(int sock, int fd);
int recvfd(int s);
int fd_received;
int main(int argc, char *argv[]) {
struct sockaddr_un addr;
char buf[100];
buf[0]='\n';
int fd,rc,confd;
int temp,len;
temp=1;
if (argc > 1) socket_path=argv[1];
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (*socket_path == '\0') {
*addr.sun_path = '\0';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
} else {
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
}
if(connect(fd,(struct sockaddr*)&addr,sizeof(addr))==-1)
{
perror("connect error");
exit(-1);
}
fd_received=recvfd(fd);
lseek(fd_received,0,SEEK_SET);
len=read(fd_received,buf,5);
if(len<0)
{
perror("read error");
}
printf("(fd_received=%d,len=%d) first %d characters read from the file whoes fd was received(content within ##) ##%.*s##\n",fd_received,len,5,5,buf);
return 0;
}
int sendfd(int sock, int fd)
{
struct msghdr hdr;
struct iovec data;
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char dummy = '*';
data.iov_base = &dummy;
data.iov_len = sizeof(dummy);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_name = NULL;
hdr.msg_namelen = 0;
hdr.msg_iov = &data;
hdr.msg_iovlen = 1;
hdr.msg_flags = 0;
hdr.msg_control = cmsgbuf;
hdr.msg_controllen = CMSG_LEN(sizeof(int));
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int*)CMSG_DATA(cmsg) = fd;
int n = sendmsg(sock, &hdr, 0);
if(n == -1)
printf("sendmsg() failed: %s (socket fd = %d)\n", strerror(errno), sock);
return n;
}
int recvfd(int s)
{
int n;
int fd;
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
char cms[CMSG_SPACE(sizeof(int))];
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = sizeof cms;
if((n=recvmsg(s, &msg, 0)) < 0)
return -1;
if(n == 0){
perror("unexpected EOF");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
On running client (recvfd) I get segmentation fault.
./recvfd
[1] 6104 segmentation fault (core dumped) ./recvfd
Here are lines from running gdb with coredump
Core was generated by `./recvfd'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000400cf9 in recvfd (s=3) at recvfd.c:146
146 memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
Here is the core dump - Link.
I want to sniff the communication happening between the two processes when the file descriptor is being sent. I am not able to figure out why the client crashes when run with socat, but doesn't when run without it.
Update 1
While using socat to sniff communication happening between two processes of a well established open source project (ivshmem - used for sharing memory between running virtual machines, also a part of Intel DPDK, Link), I observed the following.
None of the processes crash on using socat
When socat is used, the file descriptor is not properly sent, and does not get added to the recipient process.
When socat is not used, and the two processes are connected directly, the file descriptor gets sent properly, and gets added to the recipient process.
I am trying to understand procfs for communication between userspace and kernel module. My module has basic two functions for procfs write_proc, driver_mmap.
I call multiple times write_proc by calling fputs("123456789",fd). where fd is file descriptor to procfs entry in /proc directory. But I don't see write_proc called multiple time. Code is attached by here.
<code>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mm.h> /* mmap related stuff */
#define BUF_SIZE 64 * 1024
int *MmapBuffer;
int Factor = 1;
static int write_proc(struct file *filp, int *buf, size_t count, loff_t *offp)
{
int rc,i;
printk("in Write \n");
for (i = 1; i <= 16*1024 ; i++)
MmapBuffer[i-1] = (i+1)*Factor;
Factor++;
return count;
}
static int driver_mmap(struct file *file, struct vm_area_struct *vma)
{
int ret;
vma->vm_flags |= VM_LOCKED|VM_SHARED;
ret = remap_pfn_range(vma, vma->vm_start,
virt_to_phys(MmapBuffer) >> PAGE_SHIFT,
vma->vm_end-vma->vm_start, vma->vm_page_prot);
if(ret != 0)
printk("MMAP Failed \n");
SetPageReserved(virt_to_page(MmapBuffer));
printk("MMAP Succeeded \n");
return 0;
}
// file operations
struct file_operations proc_fops =
{
.write = write_proc,
.mmap = driver_mmap,
};
// init module
int init_module_test(void)
{
printk("<1>Hello world\n");
MmapBuffer = kzalloc(BUF_SIZE,__GFP_COLD|GFP_DMA);
if(MmapBuffer == NULL)
printk("Kzalloc failed. reduce buffer size \n");
proc_create ("Test_fs",0,NULL, &proc_fops);
return 0;
}
// exit module
void cleanup_module_test(void)
{
kfree(MmapBuffer);
remove_proc_entry ("Test_fs", NULL);
printk("Goodbye world\n");
}
module_init(init_module_test);
module_exit(cleanup_module_test);
MODULE_LICENSE("GPL");
</code>
Application code
<code>
#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>
#include<errno.h>
#include <fcntl.h>
int main(void)
{
int fd;
int i,j;
int *msg ;
printf("Allocation started \n ");
msg=(int*)malloc(64*1024);
if(msg == NULL)
printf("Allocation failed \n");
//unsigned int *addr;
printf("Starting opening \n ");
if((fd=open("/proc/Test_fs", O_RDONLY ))<0)
{
printf("File not opened ");
}
printf("Starting mapping \n ");
msg = mmap(NULL, 64*1024, PROT_READ, MAP_SHARED , fd, 0);
printf("done from module \n ");
if(msg == MAP_FAILED)
{
printf("MAP failed and error is %s", strerror(errno));
return 0;
}
close(fd);
printf("Successful mapping");
FILE *f;
f=fopen("/proc/Test_fs", "wr");
if(!f)
{
printf("File not opened ");
}
for (j = 0; j < 10 ; j++)
{
if(fputs("1234567890,",f) <= 0)
printf("write failed, ");
for (i = 0; i < 16*1024 ; i++)
printf("%d, ", msg[i]);
printf("\n \n done \n \n ");
}
fclose(f);
return 0;
}
</code>
Why? I didn't do anything on the other peer!
I was using massive threads to get data from the server. When the thread count is small, it's ok. But when the thread count is very large, recv() return -1 and errno indicates "Connection reset by peer".
Here is an example to reproduce the issue:
server.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* server_thread(void* arg)
{
int socket_fd = (int) ((long) arg);
// recv some info first
recv_all(socket_fd, buffer, 1, 0);
// simulate some computation
for (int i = 0; i < 0xffff; i ++)
for (int j = 0; j < 0xffff; j ++);
// send data
for (int i = 0; i < 4096; i ++)
send_all(socket_fd, buffer, sizeof(buffer), 0);
// the peer is closed, return 0
recv(socket_fd, buffer, 1, MSG_WAITALL);
close(socket_fd);
pthread_detach(pthread_self());
return NULL;
}
int main(void)
{
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
assert(listen_socket != -1);
struct sockaddr_in listen_address;
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(11282);
listen_address.sin_addr.s_addr = INADDR_ANY;
int result = bind(listen_socket,
(struct sockaddr*) &listen_address,
sizeof(listen_address));
assert(result != -1);
result = listen(listen_socket, 5);
assert(result != -1);
while (true)
{
int server_socket = accept(listen_socket, NULL, NULL);
assert(server_socket != -1);
pthread_t tid;
result = pthread_create(&tid,
NULL,
server_thread,
(void *) ((long) server_socket));
assert(result != -1);
}
return 0;
}
client.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
pthread_t threads[4096];
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* client_thread(void* arg)
{
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(socket_fd != -1);
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(11282);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
int result = connect(socket_fd,
(struct sockaddr *) &server_address,
sizeof(server_address));
assert(result != -1);
// send some info first
send_all(socket_fd, buffer, 1, 0);
// recv the reply data
for (int i = 0; i < 4096; i ++)
recv_all(socket_fd, buffer, sizeof(buffer), 0);
close(socket_fd);
return NULL;
}
int main(int argc, char* argv[])
{
assert(argc == 2);
// get client thread count
int thread_count = atoi(argv[1]);
assert(thread_count <= 4096);
for (int i = 0; i < thread_count; i ++)
{
int result = pthread_create(&threads[i], NULL, client_thread, NULL);
assert(result != -1);
}
for (int i = 0; i < thread_count; i ++)
pthread_join(threads[i], NULL);
return 0;
}
Usage:
./server
./client [thread_count]
I was using 480 as the thread_count, sometime I could reproduce the issue.
My goal is to set 2 threads for serial ports: one for read, one for write.
My example is refer to the [one](//refer to how to open, read, and write from serial port in C) heavily, but I added pthread to my code:
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
//refer to https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h> /* POSIX Threads */
#define MAX_STR_LEN 256
/*
* The values for speed are
* B115200, B230400, B9600, B19200, B38400, B57600, B1200, B2400, B4800, etc
*
* The values for parity are 0 (meaning no parity),
* PARENB|PARODD (enable parity and use odd),
* PARENB (enable parity and use even),
* PARENB|PARODD|CMSPAR (mark parity),
* and PARENB|CMSPAR (space parity).
* */
int SetInterfaceAttribs(int fd, int speed, int parity)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) /* save current serial port settings */
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return -1;
}
return 0;
}/*set_interface_attribs*/
void SetBlocking(int fd, int should_block)
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0)
{
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
return;
}
tty.c_cc[VMIN] = should_block ? 1 : 0;
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
if (tcsetattr (fd, TCSANOW, &tty) != 0)
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
}/*SetBlocking*/
void *sendThread(void *parameters)
{
char sendBuff[MAX_STR_LEN];
memset(&sendBuff[0], 0, MAX_STR_LEN);
snprintf(&sendBuff[0], MAX_STR_LEN, "hello!");
int fd;
fd = *((int*)parameters);
while(1)
{
write(fd, &sendBuff[0], strlen(&sendBuff[0]) );
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((strlen(&sendBuff[0]) + 25) * 100);
}/*while*/
pthread_exit(0);
}/*sendThread */
void *readThread(void *parameters)
{
char readBuff[MAX_STR_LEN];
int fd;
fd = *((int*)parameters);
while(1)
{
ssize_t len;
memset(&readBuff[0], 0, MAX_STR_LEN);
len = read(fd, &readBuff[0], MAX_STR_LEN);
if (len == -1)
{
switch(errno)
{
case EAGAIN:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
usleep(5*1000);
continue;
break;
default:
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
pthread_exit(0);
break;
}
}
// sleep enough to transmit the length plus receive 25:
// approx 100 uS per char transmit
usleep((len + 25) * 100);
printf("len = %d\n", (int)len);
int i;
for(i = 0; i< len; i++)
printf("%c(%d %#x)\t", readBuff[i], readBuff[i], readBuff[i]);
printf("\n");
}/*while*/
pthread_exit(0);
}/*readThread */
int main(int argc, char *argv[])
{
int fd, c, res;
struct termios oldtio,newtio;
char buf[MAX_STR_LEN];
int k;
char deviceName[MAX_STR_LEN];
memset(&deviceName[0], 0, MAX_STR_LEN);
snprintf(&deviceName[0], MAX_STR_LEN, "/dev/ttyUSB0");
k = 1;
while(argc > k)
{
if(0 == strncmp(argv[k], "-d", MAX_STR_LEN))
{
if(k + 1 < argc)
{
snprintf(&deviceName[0], MAX_STR_LEN, "%s", argv[k + 1]);
}
else
{
printf("error : -d should be follow a device!\n");
return 0;
}/*if */
}
k++;
}/*while k*/
printf("__FUNCTION__ = %s, __LINE__ = %d\n", __FUNCTION__, __LINE__);
fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
if(0 > fd)
{
perror(&deviceName[0]);
exit(-1);
}/*if */
SetInterfaceAttribs(fd, B115200, 0); /* set speed to 115,200 bps, 8n1 (no parity)*/
SetBlocking(fd, 1);
pthread_t readThread_t, sendThread_t; /* thread variables */
pthread_create(&sendThread_t, NULL, (void *)sendThread, (void *)&fd);
pthread_create(&readThread_t, NULL, (void *)readThread, (void *)&fd);
pthread_join(sendThread_t, NULL);
pthread_join(readThread_t, NULL);
close(fd);
return 0;
}/*main*/
The send data thread works well.
But the read data thread : I could not set it as blocking, the read function returns immediately, even the read data length is zero.
How should I modify the code to make the read function be blocked?
fd = open(&deviceName[0], O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
Try removing O_NONBLOCK and O_NDELAY from your open call. Or is there a particular reason you have that even though you specifically want it to block?