41、linux系統進程間有哪些通信方式
? ? ? ?管道、有名管道、消息隊列、信號、共享內存、socket、文件
? ? ? ?管道及有名管道:管道可用于具有親緣關系進程間的通信,例如父子進程,但是有名管道允許無關系的進程間通信。管道其實就是建立一個FIFO文件,一個進程往里面寫數據,另外的進程讀取數據。
demo如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main()
{
pid_t pid;
char buf[1024];
int fd[2];
char *p = "test for pipe\n";
if (pipe(fd) == -1)
sys_err("pipe");
pid = fork();
if (pid < 0)
{
sys_err("fork err");
}
else if(pid == 0)
{
//父進程
close(fd[1]);
int len = read(fd[0], buf, sizeof(buf));
write(STDOUT_FILENO, buf, len); //輸出到屏幕
close(fd[0]);
}
else
{
//子進程
close(fd[0]);
write(fd[1], p, strlen(p)); //寫入test for pipe
wait(NULL);
close(fd[1]);
}
return 0;
}
? ? ? ?消息隊列:也叫報文隊列,消息隊列是消息的鏈接表,包括Posix消息隊列和SystemV消息隊列,有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的信息,消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩沖區大小受限等缺點。
發送消息demo如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main(void)
{
int running = 1;
struct my_msg_st some_data;
int msgid = 0;
char buffer[BUFSIZ] = {0};
memset((void*)&some_data, 0, sizeof(some_data));
/*創建消息隊列*/
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid==-1)
{
fprintf(stderr,"msgget failed with error:%d\n",errno);
exit(EXIT_FAILURE);
}
/*循環向消息隊列中添加消息*/
while(running)
{
memset(buffer, 0, sizeof(buffer));
printf("Enter some text:");
fgets(buffer,BUFSIZ,stdin);
some_data.my_msg_type=1;
strcpy(some_data.some_text,buffer);
/*添加消息*/
if(msgsnd(msgid,(void *)&some_data,BUFSIZ,0)==-1)
{
fprintf(stderr,"msgsed failed\n");
exit(EXIT_FAILURE);
}
/*用戶輸入的為“end”時結束循環*/
if(strncmp(buffer,"end",3)==0)
{
running=0;
}
}
exit(EXIT_SUCCESS);
}
接收消息demo如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};
int main(void)
{
int running=1;
int msgid = 0;
struct my_msg_st some_data;
long int msg_to_receive=0;
memset((void*)&some_data, 0, sizeof(some_data));
/*創建消息隊列*/
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid==-1)
{
fprintf(stderr,"msgget failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
/*循環從消息隊列中接收消息*/
while(running)
{
/*讀取消息*/
if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1)
{
fprintf(stderr,"msgrcv failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
printf("接收到的消息為: %s",some_data.some_text);
/*接收到的消息為“end”時結束循環*/
if(strncmp(some_data.some_text,"end",3) == 0)
{
running=0;
}
}
/*從系統內核中移走消息隊列*/
if(msgctl(msgid,IPC_RMID,0) == -1)
{
fprintf(stderr,"msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
? ? ? ?信號:信號是比較復雜的通信方式,用于通知接收進程有某種事情發生,除了用于進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信息語義函數signal外,還支持語義符合Posix 1標準的信號函數sigaction。
? ? ? ?共享內存:共享內存是一種文件映射,使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其他通信機制,如信號量結合使用,來達到進程間的同步及互斥。
demo如下:
寫入共享內存:
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>
typedef struct _Teacher
{
char name[64];
int age;
}Teacher;
int main(int argc, char *argv[])
{
int ret = 0;
int shmid = 0;
//創建共享內存 ,相當于打開文件,文件不存在則創建
shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget err");
return errno;
}
printf("shmid:%d \n", shmid);
Teacher *p = NULL;
//將共享內存段連接到進程地址空間
p = (Teacher*)shmat(shmid, NULL, 0);//第二個參數shmaddr為NULL,核心自動選擇一個地址
if (p == (void *)-1 )
{
perror("shmget err");
return errno;
}
strcpy(p->name, "aaaa");
p->age = 33;
//將共享內存段與當前進程脫離
shmdt(p);
printf("鍵入1 刪除共享內存,其他不刪除\n");
int num = 0;
scanf("%d", &num);
if (num == 1)
{
//用于控制共享內存
ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID為刪除內存段
if (ret < 0)
{
perror("rmerrr\n");
}
}
return 0;
}
從共享內存讀取:
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>
typedef struct _Teacher
{
char name[64];
int age;
}Teacher;
int main(int argc, char *argv[])
{
int ret = 0;
int shmid = 0;
//打開獲取共享內存
shmid = shmget(0x2234, 0, 0);
if (shmid == -1)
{
perror("shmget err");
return errno;
}
printf("shmid:%d \n", shmid);
Teacher *p = NULL;
//將共享內存段連接到進程地址空間
p = (Teacher*)shmat(shmid, NULL, 0);
if (p == (void *)-1 )
{
perror("shmget err");
return errno;
}
printf("name:%s\n", p->name);
printf("age:%d \n", p->age);
//將共享內存段與當前進程脫離
shmdt(p);
printf("鍵入1 程序暫停,其他退出\n");
while(1)
{
sleep(1);
}
return 0;
}
? ? ? ?socket:socket也就是套接字,最普遍的進程間通信機制,可用于不同機器之間的進程間通信。
42、為什么要使用linux作為服務器。
? ? ? ?首先,linux是免費的,而windows需要向微軟購買正版授權;
? ? ? ?其次,linux比windows靈活,可以實現很多定制化需求,因為linux可以修改系統內核;
? ? ? ?再次,很多高端服務器組件對linux支持的更好,windows版本的可能功能都不是很完整;
? ? ? ?最后,linux開源,所以很多人為它添磚加瓦,幾乎你需要的功能都能找到linux的版本并且都是開源免費的。
43、mysql數據庫的引擎
? ? ? ?你能用的數據庫引擎取決于mysql在安裝的時候是如何被編譯的。要添加一個新的引擎,就必須重新編譯mysql,在缺省情況下,mysql支持三個引擎:ISAM、MYISAM和HEAP,另外兩種類型INNODB和BERKLEY,也常常可以使用。
- ISAM
? ? ? ?ISAM是一個定義明確且歷經時間考驗的數據庫表格管理方法,它在設計之時就考慮到數據庫被查詢的次數要遠大于更新的次數。因此,ISAM執行讀取操作的速度很快,而且不占用大量的內存和存儲資源。ISAM的兩個主要不足之處在于,它不支持事務處理,也不能夠容錯,如果你的硬盤崩潰了,那么數據文件就無法恢復了。如果你正在把ISAM用在關鍵任務應用程序里,那就必須經常備份你所有的實時數據,通過其復制特性,Mysql能夠支持這樣的備份應用程序。 - MYISAM
? ? ? ?MYISAM是MySQL的ISAM擴展格式和缺省的數據庫引擎,除了提供ISAM里所沒有的索引和字段管理的大量功能,MYISAM還使用一種表格鎖定的機制,來優化多個并發的讀寫操作。其代價是你需要經常運行OPTIMIZE TABLE命令,來恢復被更新機制所浪費的時間。MYISAM還有一些有用的擴展,例如用來修復數據庫文件的MYISAMCHK工具和用來恢復浪費空間的MYISAMPACK工具。
? ? ? ?MYISAM強調了快速讀取操作,這可能就是為什么MYSQL受到了WEB開發如此青睞的主要原因,在WEB開發中你所進行的大量數據操作都是讀取操作。所以,大多數虛擬主機提供商和INTERNET平臺提供商只允許使用MYISAM格式。 - HEAP
? ? ? ?HEAP允許只駐留在內存里的臨時表格。駐留在內存使得HEAP比ISAM和MYISAM的速度都快,但是它所管理的數據是不穩定的,而且如果在關機之前沒有進行保存,那么所有的數據都會丟失。在數據行被刪除的時候,HEAP也不會浪費大量的空間,HEAP表格在你需要使用SELECT表達式來選擇和操控數據的時候非常有用。要記住,用完表格后要刪除表格。 - INNODB和BERKLEYDB
? ? ? ?INNODB和BERKLEYDB數據庫引擎都是造就MYSQL的靈活性技術的直接產品,這項技術就是mysql++API。在使用mysql的時候,你所面對的每一個挑戰幾乎都源于ISAM和MYISAM數據庫引擎不支持事務處理也不支持外來鍵。盡管要比ISAM和MYISAM引擎慢很多,但是INNODB和BERKLEYDB包括了對事務處理和外來鍵的支持,這兩點都是前兩個引擎所沒有的。如前所述,如果你的設計需要這些特性中的一者或者兩者,那你就要被迫使用后兩個引擎中的一個了。
44、什么是紅黑樹?
? ? ? ?紅黑樹,又叫RB樹,是一種特殊的二叉查找樹,可以自動排序,且紅黑樹的每個節點都有存儲位表示節點的顏色,標識是紅或者黑。
? ? ? ?紅黑樹的特性:
? ? ? ?每個節點或者是黑色,或者是紅色;
? ? ? ?跟節點是黑色;
? ? ? ?每個葉子節點是黑色(這里葉子節點是指沒有子節點的葉子節點);
? ? ? ?如果一個節點是紅色的,則它的子節點必為黑色的;
? ? ? ?從一個節點到該節點子孫節點的所有路徑上包含相同數目的黑節點。
45、C程序的內存分配方式
? ? ? ?由上到下(地址從高到低):棧、動態鏈接庫、堆、bbs(未初始化的全局變量)、數據段(存放初始化的全局變量)、文本段(存放代碼)
46、select和epoll的區別
? ? ? ?select函數 int select(int n,fd_set* readfds, fd_set* writefds, fd_set* errorfds, struct timeval* timeout);
? ? ? ?第一個參數n代表最大的文件描述符+1
? ? ? ?fd_set是一個集合,存放的是文件描述符
? ? ? ?readfds表示我們要監視這些文件描述符里讀變化
? ? ? ?writefds表示我們要監視它所指向的集合里面的文件描述符的寫變化
? ? ? ?errorfds表示要監視文件描述符是否發生了錯誤異常
? ? ? ?timeout若為NULL,則select置于阻塞狀態,直到監視的某個文件描述符發生變化才返回
? ? ? ?timeout若等于0秒0毫秒,則select是一個純粹的非阻塞函數,不管文件描述符是否變化,立即返回。
? ? ? ?timeout大于0時,則在timeout時間內阻塞,timeout時間內若文件描述符有變化則返回,如果超時則立即返回
? ? ? ?返回值:負值 select發生錯誤
? ? ? ?正值 有文件描述符發生變化
? ? ? ?0 等待超時,沒有可讀寫或者發生錯誤的文件描述符
? ? ? ?epoll函數與select函數最大的不同在于它不會隨著監聽fd數目的增長而降低效率,并且select同時監聽的fd數目是有限制的,默認最大是1024.
? ? ? ?int epoll_create(int size);//創建epoll句柄,參數size告訴內核這個監聽的數目有多大,但最新版本這個參數已經無用了
? ? ? ?int epoll_ctl(); //epoll的事件注冊函數,它要先注冊需要監聽的事件類型
? ? ? ?int epoll_wait();//等待事件的發生
? ? ? ?select是輪詢fd,而epoll是先將文件描述符注冊到內核,一旦文件描述符發生變化,內核會采用回調機制,激活這個文件描述符,這樣epoll_wait便會知道。
? ? ? ?epoll相對于select優點:
? ? ? ?監視的文件描述符不受限制,具體多少根內存有關
? ? ? ?IO的效率不會隨著監視fd的數量的增加而降低
? ? ? ?mmap加速內核與用戶空間的信息傳遞,避免了多余的內存拷貝
47、linux下inode的說明
? ? ? ?每個磁盤空間都有一個inode表,inode里面每一個節點存放該空間每個文件的信息,例如:文件的字節數、文件擁有者、所在的組、權限、時間、位置等。
? ? ? ?istat 命令查看單個文件;
? ? ? ?df –i查看磁盤空間inode的使用量。
48、IP、TCP、UDP數據包大小
? ? ? ?MTU,普通局域網最大傳輸單元,為1500個字節;
? ? ? ?IP數據包首部20個字節,所以IP數據包一般是1480個字節;
? ? ? ?TCP數據包首部20個字節,所以數據包大小為1460個字節;
? ? ? ?UDP數據包首部8個字節,所以數據包大小我1472個字節;
? ? ? ?注意:這里說的首部是固定長度,但后面還有一些可選字段。
49、memcache的特性
? ? ? ?服務器接到客戶端請求會先檢查memcached,如有則直接返回,不再檢查DB
? ? ? ?如memcache沒有要找的數據,則檢查DB,查到以后返回給客戶端,并同時緩沖一份到memcache
? ? ? ?更新DB同時更新memcache,保證數據的一致性
? ? ? ?當分配給memcache內存空間用完之后,會根據LRU(最近最少使用)策略和到期失效策略,先替換失效數據,再替換最近最少使用數據
? ? ? ?memchche在內存中是一個巨大的hast表,它其實就是讀數據庫改為直接讀內存,提高讀取速度
50、什么是sql注入
? ? ? ?sql注入:用戶可以提交一段數據庫查詢代碼,根據程序返回的結果,獲得某些他想得知的數據。
? ? ? ?應對辦法:可以通過數據庫防火墻實現對sql注入攻擊的防范,因為sql注入攻擊往往是通過應用程序來進攻,可以使用虛擬補丁技術實現,對注入攻擊的sql特征識別,實現實時攻擊阻斷。