我正在做一個學校專案,我遇到了一些理論上不應該起作用的東西。
我需要創建兩個程式,其中一個通過 unix 信號與另一個通信,我將它們稱為客戶端和服務器,我在客戶端的 argv 中傳遞一條訊息,將每個字符分解為位并發送到服務器
這個想法是使用按位通信(一些簡單和基本的東西,如果位是 0,我使用 kill 系統呼叫將 SIGUSR1 發送到服務器 PID,如果是 1,我發送 SIGUSR2。
#client send a char to server
int send_sig(int pid, unsigned char b)
{
int a;
a = 0;
while (a < 8)
{
if (b & 1)
kill(pid, SIGUSR2);
else
kill(pid, SIGUSR1);
b = b >> 1;
a ;
usleep(1000);
}
return (0);
}
問題是當我使用 unicode 字符時,argv 將始終是一個字串(一個 char 陣列),所以當我傳遞一些 unicode 字符時,它會在 1 到 4 個位元組之間變化,即使程序繼續正常,問題也會發生在我的我得到這些位的服務器端
我構建代碼的方式是我需要一次列印一位(這是可以接受的,因為理論上 C 中的一個 char 相當于一個位元組)但即使傳遞 4 位元組 unicode 字符,一次列印一個它繼續作業(就像俄羅斯輪盤賭,有時會中斷,有時會正常作業)
# Server receiving the
unsigned char reverse(unsigned char b)
{
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return (b);
}
void signal_handler(int sig, siginfo_t *p_info, void *ucontext)
{
static unsigned int a = 0;
static unsigned int b = 0;
a <<= 1;
if (sig == SIGUSR2)
a ;
b ;
if (b == 8)
{
b = 0;
ft_printf("%c\0", reverse(a));
}
p_info = p_info;
ucontext = ucontext;
}
為什么會發生這種行為?不只是為了打破和列印錯誤嗎?
預期:
我在沒有 NULL 位元組的標準輸出上列印的方式使 shell 和終端解釋器成為一個完整的位元組,而不會丟失 UTF-8 映射
char 中的 unicode fitt (但我猜這是不可能的)
使用這些代碼重現此行為:
#client.c file
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void send_sig(int pid, char b)
{
int a = 0;
printf("%c", b);
while (a < 8)
{
if (b & 1)
kill(pid, SIGUSR2);
else
kill(pid, SIGUSR1);
b >>= 1;
a ;
usleep(500);
}
}
int main(int argc, char *argv[])
{
char *s = "??????????????";
while (*s != '\0')
send_sig(atoi(argv[1]), *s);
}
#server.c file
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
unsigned char reverse(unsigned char b)
{
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return (b);
}
void signal_handler(int sig, siginfo_t *p_info, void *ucontext)
{
static unsigned int a = 0;
static unsigned int b = 0;
a <<= 1;
if (sig == SIGUSR2)
a ;
b ;
if (b == 8)
{
b = 0;
a = reverse(a);
write(1, &a, 1);
}
p_info = p_info;
ucontext = ucontext;
}
int main(void)
{
struct sigaction act;
act.sa_sigaction = signal_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGUSR1, &act, NULL);
sigaction(SIGUSR2, &act, NULL);
printf("The server pid: %d\n", getpid());
while (1)
usleep(300);
}
uj5u.com熱心網友回復:
可以通過發送 16 (UTF-16) 或 32 (UTF-32) 位值(這意味著字符傳輸始終為 16 或 32 位長)或逐位元組來實作逐位發送 unicode。如果是后者,則第一個位元組確定傳輸中的位元組數(位)。目前,您的服務器僅讀取 8 位并將接收到的位元組發送到輸出,其余的(可能的多位元組字符)位元組不被考慮和丟棄。
如果您的服務器有第一個位元組(8 位),則執行以下操作來計算傳輸中的位元組數:
if (byte < 0x80)
num_bytes = 1; //single byte, no further read required
else if ((byte & 0xe0) == 0xc0)
num_bytes = 2; //one more byte to read
else if ((byte & 0xf0) == 0xe0)
num_bytes = 3; //two more bytes to read
else if ((byte & 0xf8) == 0xf0)
num_bytes = 4; //three more bytes to read
然后,要形成有效的 utf8(多位元組)字符,請將以下(如果有)位元組讀入 char 陣列,例如unsigned char utf8_bytes[4];
當然,為了形成一個有效的以空字符結尾(可列印)的字串,陣列的大小必須是5,最后一個位元組設定為'\0'.
添加
您的客戶端正在發送位序列(位元組:10101010),如下所示:
1010101|0 -> SIGUSR1
101010|1 -> SIGUSR2
10101|0 -> SIGUSR1
1010|1 -> SIGUSR2
101|0 -> SIGUSR1
10|1 -> SIGUSR2
1|0 -> SIGUSR1
|1 -> SIGUSR2
因此,每次您的服務器接收到SIGUSR2時,它都必須將位設定在某個位置,這可以像這樣輕松完成:
if (sig == SIGUSR2)
byte |= (1 << bit_counter);
bit_counter;
完整的服務器代碼可能如下所示:
void signal_handler(int sig, siginfo_t *p_info, void *ucontext)
{
static unsigned char utf8_bytes[5]; //multibyte storage
static unsigned char byte = 0; //bitset
static int byte_index = 0; //current position in the mb storage
static int bit_counter = 0; //number of bits received
static int num_bytes = 1; //total number of bytes of mb character
if (sig == SIGUSR2) //bit: 1
byte |= (1 << bit_counter); //set the according bit in byte
if ( bit_counter == 8) { //we received 8 bits -> 1 byte
if (byte_index == 0) { //if first byte in sequence
if (byte < 0x80)
num_bytes = 1; //single byte, no further read required
else if ((byte & 0xe0) == 0xc0)
num_bytes = 2; //one more byte to read
else if ((byte & 0xf0) == 0xe0)
num_bytes = 3; //two more bytes to read
else if ((byte & 0xf8) == 0xf0)
num_bytes = 4; //three more bytes to read
}
//since we completed 1 byte, decrease num_bytes
if (--num_bytes == 0) { //and if there are no more bytes to read
utf8_bytes[ byte_index] = '\0'; //make null-terminated string
//printf("%s\n", utf8_bytes); //do something useful
byte_index = 0; //reset the byte index
} else { //we need further reading
utf8_bytes[byte_index ] = byte; //store the byte
}
bit_counter = 0; //reset counter
byte = 0; //reset byte (set all bits to zero)
}
p_info = p_info;
ucontext = ucontext;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/531355.html
標籤:Clinux壳终端信号
上一篇:使用bash腳本順序輸出多ssh
