![](/img/trans.png)
[英]How to add delay to sento and recvfrom in UDP client/server in C
[英]How to stop recvfrom() from blocking while using in threads with UDP server in C linux?
我在兩台計算機之間實現服務器-客戶端,想法是從連接的從機讀取輸入到 PC3 並將其發送到 PC4 以及返回的方式(來自連接的從機 P4 的輸入並將其發送到 PC3)。
服務器端:
client:
static void FSoEThread()
{
struct timeval time1;
uint8_t pdu_in_local[sizeof(pdu_in)];
uint8_t pdu_out_local[sizeof(pdu_out)];
uint8_t pdu_in_tmp[sizeof(pdu_in)];
uint8_t pdu_out_tmp[sizeof(pdu_out)];
FILE *fp;
fp = fopen("Log.txt", "w");//opening file.
SerialPort sp(MODEMDEVICE);
int socket_desc;
struct sockaddr_in server_addr;
unsigned int server_message[255], client_message[255];
socklen_t server_struct_length = sizeof(server_addr);
;
printf("Thread_quit\n");
while(!thread_quit){
std::vector<uint8_t> uart_in(10);
sp.Read(uart_in);
if(1){
switch(ecatGetMasterState())
{
default:
break;
case _UNKNOWN:
case _INIT:
case _PREOP:
case _SAFEOP:
break;
case eEcatState_OP:
{
{
uint8_t buf[sizeof(pdu_in)]; // In data comes from Slave
if(uart_in.size() == 10){
PD_mutex.lock();
memcpy(pdu_out,&uart_in.data()[4],sizeof(pdu_out));//out data coming from Master to the Slave
memcpy(pdu_out_local,&uart_in.data()[4],sizeof(pdu_out));
memcpy(buf,pdu_in,sizeof(pdu_in));
memcpy(pdu_in_local,pdu_in,sizeof(pdu_in));
PD_mutex.unlock();
printf("\n");
sp.Write(buf,sizeof(pdu_in));
}
}
gettimeofday(&time1,NULL);
if(memcmp(pdu_in_tmp,pdu_in_local,sizeof(pdu_in)) != 0){
memcpy(pdu_in_tmp,pdu_in_local,sizeof(pdu_in));
fprintf(fp,"[%05d.%06d]in %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
(unsigned int)pdu_in_tmp[0],
(unsigned int)pdu_in_tmp[1],
(unsigned int)pdu_in_tmp[2],
(unsigned int)pdu_in_tmp[3],
(unsigned int)pdu_in_tmp[4],
(unsigned int)pdu_in_tmp[5]
);
unsigned int *PDU_UDP_IN = (unsigned int*)pdu_in_tmp;
// Create socket:
socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socket_desc < 0){
printf("Error while creating socket\n");
exit(1);
}
// Clean buffers:
memset(server_message, 0, sizeof(server_message));
memset(client_message, 0, sizeof(client_message));
// Set port and IP:
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(2000);
server_addr.sin_addr.s_addr = inet_addr("10.100.20.54");
printf("sending\n");
// Send the message to server:
if(sendto(socket_desc, PDU_UDP_IN, sizeof(PDU_UDP_IN), 0,
(struct sockaddr*)&server_addr, server_struct_length) < 0){
printf("Unable to send message\n");
exit(1);
}
printf("sendto: msg send to IPC4 :\t%x\n",*PDU_UDP_IN);
socklen_t server_struct_length = sizeof(server_addr);
//recvfrom(socket_desc, server_message, sizeof(server_message), 0,(struct sockaddr*)&server_addr, &server_struct_length);
//if(int errn_ = recvfrom(socket_desc, server_message, sizeof(server_message), 0,(struct sockaddr*)&server_addr, &server_struct_length) < 0){
//printf("Error while receiving server's msg\n");
//printf("n=%d, Errno%d\n",errn_,errno);
//exit(1);
//}
printf("Recved\n");
printf("MSG from IPC4:\t%x\n",*server_message);
close(socket_desc);
}
if(memcmp(pdu_out_tmp,pdu_out_local,sizeof(pdu_out)) != 0){
memcpy(pdu_out_tmp,pdu_out_local,sizeof(pdu_out));
fprintf(fp,"[%05d.%06d]out %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
(unsigned int)pdu_out_tmp[0],
(unsigned int)pdu_out_tmp[1],
(unsigned int)pdu_out_tmp[2],
(unsigned int)pdu_out_tmp[3],
(unsigned int)pdu_out_tmp[4],
(unsigned int)pdu_out_tmp[5]
);
}
}
}
}
}
pthread_exit(NULL);
}
這面如果工作得好……它可以發送和接收……
現在發生問題的客戶端....說我在客戶端(PC3)的這一側評論/刪除recvfrom ..所有工作正常(服務器端recvfrom和sendto也可以工作,我獲取數據並可以發送數據)嘗試時接收(在客戶端再次使用 recvfrom 函數)數據交換 4 次,然后客戶端和服務器都不再執行任何操作 -> 我將陷入死鎖,並且兩者都在 RECVFROM 中被阻塞
static void FSoEThread()
{
struct timeval time1;
uint8_t pdu_in_local[sizeof(pdu_in)];
uint8_t pdu_out_local[sizeof(pdu_out)];
uint8_t pdu_in_tmp[sizeof(pdu_in)];
uint8_t pdu_out_tmp[sizeof(pdu_out)];
int socket_desc;
struct sockaddr_in server_addr, client_addr;
unsigned int server_message[255], client_message[255];
socklen_t client_struct_length = sizeof(client_addr);
// Clean buffers:
memset(server_message, '\0', sizeof(server_message));
memset(client_message, '\0', sizeof(client_message));
FILE *fp;
fp = fopen("Llog.txt", "w");//opening file.
long save_fd;
SerialPort sp(MODEMDEVICE);
printf("thread_quit\n");
while(!thread_quit){
std::vector<uint8_t> uart_in(10);
sp.Read(uart_in);
if(1){
switch(ecatGetMasterState())
{
default:
break;
case _UNKNOWN:
case _INIT:
case _PREOP:
case _SAFEOP:
break;
case eEcatState_OP:
{
{
uint8_t buf[sizeof(pdu_in)];
if(uart_in.size() == 10){
PD_mutex.lock();
memcpy(pdu_out,&uart_in.data()[4],sizeof(pdu_out));
memcpy(pdu_out_local,&uart_in.data()[4],sizeof(pdu_out));
memcpy(buf,pdu_in,sizeof(pdu_in));
memcpy(pdu_in_local,pdu_in,sizeof(pdu_in));
PD_mutex.unlock();
sp.Write(buf,sizeof(pdu_in));
}
}
gettimeofday(&time1,NULL);
if(memcmp(pdu_in_tmp,pdu_in_local,sizeof(pdu_in)) != 0){
memcpy(pdu_in_tmp,pdu_in_local,sizeof(pdu_in));
fprintf(fp,"[%05d.%06d]in %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
(unsigned int)pdu_in_tmp[0],
(unsigned int)pdu_in_tmp[1],
(unsigned int)pdu_in_tmp[2],
(unsigned int)pdu_in_tmp[3],
(unsigned int)pdu_in_tmp[4],
(unsigned int)pdu_in_tmp[5]
);
unsigned int * PDU_UDP_IN = (unsigned int*)pdu_in_tmp;
printf("in \t%X\n",*PDU_UDP_IN);
// Create UDP socket:
socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socket_desc < 0){
printf("Error while creating socket\n");
exit(1);
}
// Set port and IP:
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(2000);
server_addr.sin_addr.s_addr = inet_addr("10.100.20.54");
// Bind to the set port and IP:
if(bind(socket_desc, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
exit(1);
}
//printf("Listening for incoming messages...\n\n");
// Receive client's message:
printf("Recving\n");
if (recvfrom(socket_desc, client_message, sizeof(client_message), 0,(struct sockaddr*)&client_addr, &client_struct_length) < 0){
//printf("Couldn't receive\n");
//continue;
}
printf("Received\n");
// inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
printf("msg from IPC3:\t%x\n", *client_message);
// Respond to client:
printf(" sending\n");
// strcpy(server_message, client_message);
socklen_t client_struct_length = sizeof(client_addr);
if (sendto(socket_desc, PDU_UDP_IN, sizeof(PDU_UDP_IN), 0,
(struct sockaddr*)&client_addr, client_struct_length) < 0){
printf("Can't send\n");
exit(EXIT_FAILURE);
}
printf(" sent\n");
// Close the socket:
close(socket_desc);
}
if(memcmp(pdu_out_tmp,pdu_out_local,sizeof(pdu_out)) != 0){
memcpy(pdu_out_tmp,pdu_out_local,sizeof(pdu_out));
fprintf(fp,"[%05d.%06d]out %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
(unsigned int)pdu_out_tmp[0],
(unsigned int)pdu_out_tmp[1],
(unsigned int)pdu_out_tmp[2],
(unsigned int)pdu_out_tmp[3],
(unsigned int)pdu_out_tmp[4],
(unsigned int)pdu_out_tmp[5]
);
}
}
}
}
}
pthread_exit(NULL);
}
我的問題:
1-我在這里做錯了嗎?
2-是否有任何解決方法可以以更簡單的方式克服這個問題? 我正在閱讀有關 select 但我不知道它在我使用 2 台具有不同線程的 PC 時是否有效
3-我從幾天開始就嘗試使用 MSG_DONTWAIT 之類的標志,嘗試使用 setsockopt() ...
4-有沒有辦法真正調試這種情況?
我會非常感謝你的回答
該程序真的很大......這些是UDP實現的部分......用C / C ++編寫,所有其他部分都完美無缺,問題只是知道如何讓UDP停止在recvfrom阻塞
- 我在這里做錯了嗎?
您似乎對 UDP 有很多競爭條件和誤解。
如果服務器向客戶端發送數據報,當客戶端沒有綁定套接字時——數據報就丟失了。 直到稍后才排隊。 你在反向路徑上有同樣的問題。
如果服務器和客戶端套接字都保持打開狀態,則至少數據報將排隊,直到它們的緩沖區填滿。 這使您有很好的機會在消息永遠丟失之前閱讀它。
盡管如此,在這里阻止recvfrom
肯定是一個錯誤。 數據報可能由於網絡擁塞而丟失,而無限期掛起並不是一個好的響應。
- 是否有任何解決方法可以以更簡單的方式克服此問題? 我正在閱讀有關 select 但我不知道它在我使用 2 台具有不同線程的 PC 時是否有效
如果您不知道如何使用非阻塞 UDP 來處理此問題(或者非常合理地不想花費所需的時間),請使用 TCP,並記住設置TCP_NODELAY
。
- 我一直在嘗試使用 MSG_DONTWAIT 之類的標志,嘗試使用 setsockopt()
嘗試找到TCP/IP Illustrated Vol.1的二手副本,如果可能的話,找到舊的 Stevens 版本(它缺少較新的更新,但涵蓋了基礎知識並且序列圖更好 IIRC)。 通過反復試驗來弄清楚這些東西是痛苦的。
- 有沒有辦法真正調試這種情況?
strace
下運行您的客戶端和服務器,並確保顯示所有套接字系統調用,並帶有准確(並且希望同步良好)的時間戳
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.