Socket的中文翻譯為“插座”,在計算機世界里稱為套接字。Socket最初是作為網(wǎng)絡上不同主機之間進程的通信接口,后來應用越來越廣,在同一主機上的不同進程之間通信也可以用Socket。簡單來說,當網(wǎng)絡上不同主機之間的兩個進程(A、B)采用Socket進行通信時,那么它們之間需要建立一個通信端點,即創(chuàng)建Socket,創(chuàng)建Socket時就分配端口號和網(wǎng)絡地址。當進程A向進程B發(fā)送數(shù)據(jù)時,那么進程A必須要知道進程B的網(wǎng)絡地址及端口號。
Socket采用C/S模型進行設計的,即Client/Server,面向客戶端—服務器模型。
每一個Socket都用一個半相關描述:
{協(xié)議,本地地址,本地端口}
一個完整的Socket則用一個相關描述:
{協(xié)議,本地地址,本地端口,遠程地址,遠程端口}
一、Socket的類型
Socket有三種類型:
1、字節(jié)流套接字(SOCK_STREAM)
字節(jié)流的套接字可以提供可靠的數(shù)據(jù)傳輸、面向連接的通訊流。數(shù)據(jù)按何種順序發(fā)送,就按何種順序接收。例如,當我們按順序發(fā)送A-B-C,那么在數(shù)據(jù)到達接收端時,它的順序也是A-B-C。字節(jié)流套接字采用的是TCP(Transmission Control Protocol)協(xié)議。保證了數(shù)據(jù)傳輸?shù)目煽啃浴?/p>

2、數(shù)據(jù)報套接字(SOCK_DGRAM)
數(shù)據(jù)報套接字定義了一種無連接的服務。所謂無連接服務,簡單來說,即在發(fā)送數(shù)據(jù)時,無需在收發(fā)兩端建立類似TCP那樣的握手連接,在發(fā)送時,將數(shù)據(jù)打包,然后加上遠程IP地址,即可把該數(shù)據(jù)包發(fā)送出去。
數(shù)據(jù)通過相互獨立的報文進行傳輸。并且是無序的、不可靠的傳輸。

3、原始套接字(SOCK_ROW)
原始套接字是我們需要關心的,因為我們的Socket CAN采用的即是原始套接字。該接口允許對較底層協(xié)議進行操作,如IP、ICMP等。原始套接字常用于檢驗新的協(xié)議實現(xiàn)或訪問現(xiàn)有服務中配置的新設備。
套接字的工作流程如下:
先啟動服務器,通過調用socket()函數(shù)建立一個套接字,然后調用bind()函數(shù)將該套接字和本地網(wǎng)絡地址聯(lián)系在一起,再調用listen()函數(shù)使套接字做好偵聽的準備,并規(guī)定它的請求隊列的長度,之后就調用accept()函數(shù)來接收連接。客戶端在建立套接字之后就可調用 connect()和服務器建立連接。連接一旦建立,客戶端和服務器之間就可以通過調用recv()/recvfrom()函數(shù)和send()/sendto函數(shù)來進行發(fā)收數(shù)據(jù)。最后,待數(shù)據(jù)傳送結束后,雙方調用close()函數(shù)關閉套接字。
下面我們來寫兩個簡單的基于Socket的CAN應用程序,但是我們采用的是SOCK_ROW,因此在套接字工作流程上有區(qū)別于SOCK_STREAM和SOCK_DGRAM。由于Socket采用C/S模型進行設計的,所以我們的這兩個程序也分別為Server和Client。
首先是server端的程序,我們需要寫一個服務器的程序,該程序接收來自客戶端發(fā)來的數(shù)據(jù),代碼如下:
int can_recv()
{
int sock_fd;
unsigned long nbytes, len;
struct sockaddr_can addr;
struct ifreq ifr;
/*為了能夠接收CAN報文,我們需要定義一個CAN數(shù)據(jù)格式的結構體變量*/
struct can_frame frame;
struct can_frame *ptr_frame;
/*建立套接字,設置為原始套接字,原始CAN協(xié)議*/
sock_fd = socket(PF_CAN,SOCK_RAW,CAN_RAW);
/*以下是對CAN接口進行初始化,如設置CAN接口名,即當我們用ifconfig命令時顯示的名字*/
strcpy(ifr.ifr_name,"can0");
ioctl(sock_fd, SIOCGIFINDEX, &ifr);
printf("can0 can_ifindex = %x\n",ifr.ifr_ifindex);
/*設置CAN協(xié)議*/
addr.can_family = AF_CAN;
addr.can_ifindex = 0;
/*將剛生成的套接字與網(wǎng)絡地址進行綁定*/
bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr));
/*開始接收數(shù)據(jù)*/
nbytes = recvfrom(sock_fd, &frame, sizeof(struct can_frame), 0, (struct sockaddr *)&addr, &len);
/*get interface name of the received CAN frame*/
ifr.ifr_ifindex = addr.can_ifindex;
ioctl(sock_fd, SIOCGIFNAME, &ifr);
printf("Received a CAN frame from interface %s\n",ifr.ifr_name);
/*將接收到的CAN數(shù)據(jù)打印出來,其中ID為標識符,DLC為CAN的字節(jié)數(shù),DATA為1幀報文的字節(jié)數(shù)*/
printf("CAN frame:\n ID = %x\n DLC = %x\n" \
"DATA = %s\n",frame.can_id,frame.can_dlc,frame.data);
ptr_frame = &frame;
return 0;
}
接下來是CAN的發(fā)送程序,即客戶端,代碼如下:
int can_send()
{
int sock_fd;
unsigned long nbytes;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
/*建立套接字,設置為原始套接字,原始CAN協(xié)議*/
sock_fd = socket(PF_CAN,SOCK_RAW,CAN_RAW);
/*以下是對CAN接口進行初始化,如設置CAN接口名,即當我們用ifconfig命令時顯示的名字*/
strcpy((char *)(ifr.ifr_name), "can0");
ioctl(sock_fd, SIOCGIFINDEX, &ifr);
printf("can0 can_ifindex = %x\n", ifr.ifr_ifindex);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
/*將剛生成的套接字與CAN套接字地址進行綁定*/
bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr));
/*設置CAN幀的ID號,可區(qū)分為標準幀和擴展幀的ID號*/
frame.can_id = 0x1122;
strcpy((char *)frame.data,"hello");
frame.can_dlc = strlen(frame.data);
printf("Send a CAN frame from interface %s\n", ifr.ifr_name);
/*開始發(fā)送數(shù)據(jù)*/
nbytes = sendto(sock_fd, &frame, sizeof(struct can_frame), 0, (struct sockaddr*)&addr, sizeof(addr));
return 0;
}
上面兩個程序看完后,大家可能會有疑問,為什么這兩個程序沒有l(wèi)isten()和accept()函數(shù)呢?其實這兩個程序是獨立的運行的,并不像字節(jié)流套接字(SOCK_STREAM)和數(shù)據(jù)報套接字(SOCK_DGRAM),需要先運行服務器進行偵聽。SOCK_STREAM和SOCK_DGRAM的兩個server和client程序是通過網(wǎng)絡相互收發(fā)數(shù)據(jù)。而CAN的socket的server和client程序收發(fā)數(shù)據(jù)的對象是CAN總線。server從CAN總線上接收數(shù)據(jù),client將數(shù)據(jù)發(fā)到CAN總線上,當CAN總線上有數(shù)據(jù)時,server才能接收數(shù)據(jù),當CAN總線空閑時,client才能將數(shù)據(jù)發(fā)送出去。
以上是對套接字的簡單理解,并附上socket CAN的簡單上層應用代碼。
-
CAN
+關注
關注
59文章
3067瀏覽量
472757 -
服務器
+關注
關注
14文章
10253瀏覽量
91496 -
Socket
+關注
關注
1文章
214瀏覽量
36912
原文標題:為了能夠對Socket CAN的深入理解,我們需要了解Socket的機制
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
EtherCAT FOE工作原理揭秘:客戶端-服務器模型如何運轉?
Microchip推出模型語境協(xié)議(MCP)服務器,助力AI驅動的產品數(shù)據(jù)訪問
socket是什么
Microchip推出模型語境協(xié)議服務器
DeepSeek模型如何在云服務器上部署?
【HZ-RK3568開發(fā)板免費體驗】基于 Select Poll的TCP發(fā)服務器
如何進行YOLO模型轉換?
ai服務器是什么?與普通服務器有什么區(qū)別
FA模型訪問Stage模型DataShareExtensionAbility說明
基于RAKsmart云服務器的AI大模型實時推理方案設計
AI原生架構升級:RAKsmart服務器在超大規(guī)模模型訓練中的算力突破
RAKsmart高性能服務器集群:驅動AI大語言模型開發(fā)的算力引擎
AI 推理服務器都有什么?2025年服務器品牌排行TOP10與選購技巧
Socket采用C/S模型進行設計的服務器模型
評論