uclinux多线程应用-网络通信[转]
數(shù)據(jù)通信是依照一定的協(xié)議,利用數(shù)據(jù)傳輸技術(shù)在兩個終端之間傳遞數(shù)據(jù)信息的一種通信技術(shù)。它可以實現(xiàn)計算機和計算機、計算機和終端以及終端和終端之間的數(shù)據(jù)信息傳遞。根據(jù)通信方式的不同可以分成并行通信和串行通信。在工業(yè)控制領(lǐng)域,成千上萬的具有串行接口的工業(yè)設(shè)備,如檢測器、感應(yīng)器、PLC、讀卡器等,它們無時無刻地采集現(xiàn)場數(shù)據(jù),并且想換之間通過串口連接成一個控制網(wǎng)絡(luò),作為信息系統(tǒng)內(nèi)管理數(shù)據(jù)的工具。串行通信技術(shù)作為一種靈活、方便、可靠的通信方式,長久以來一直穩(wěn)定的應(yīng)用在IT和工業(yè)通信領(lǐng)域。近年來,隨著互聯(lián)網(wǎng)技術(shù)的蓬勃發(fā)展,串行通信技術(shù)面臨著新的挑戰(zhàn)和發(fā)展空間。
由于串口通信存在的數(shù)據(jù)量小、布線困難、傳輸距離短的特點,我們需要一個更好的解決辦法,近年來出現(xiàn)的交換以太網(wǎng)克服了這些缺點。這里我們設(shè)計一個嵌入式串口協(xié)議處理系統(tǒng),來實現(xiàn)串口與網(wǎng)口數(shù)據(jù)間的傳輸。說白了,就是把從串口讀取到的數(shù)據(jù)發(fā)向網(wǎng)絡(luò),把從網(wǎng)絡(luò)讀取到的數(shù)據(jù)發(fā)向串口。在系統(tǒng)發(fā)送和接受以太網(wǎng)數(shù)據(jù)的時候,需要在這之前建立連接。并且由于在實現(xiàn)網(wǎng)絡(luò)數(shù)據(jù)傳向串口和串口數(shù)據(jù)發(fā)向網(wǎng)絡(luò)的過程是同時進(jìn)行,這就需要用到多線程技術(shù)。對于串口通信和TCP/IP協(xié)議就不過多介紹,下面直接講如何做一些簡單的編程,需要有一點C語言基礎(chǔ)。
Linux系統(tǒng)下的多線程遵循POSIX線程接口,稱為pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時需要使用庫libpthread.a(dl注:在Makefile里添加LDLIBS += -lpthread即可)。
#include <pthread.h>
在根據(jù)前面的介紹分別實現(xiàn)了串口轉(zhuǎn)網(wǎng)絡(luò)和網(wǎng)絡(luò)串口功能以后,下面需要把兩個功能分別添加進(jìn)各自的線程。這里分別命名為task和task2。
void task(int *counter);
void task2(int *counter);
用函數(shù)pthread_create來創(chuàng)建一個線程,返回0則表示創(chuàng)建成功:
pthread_create( &thrd , NULL , (void*) task , (void*) & gCounter );
用pthread_join等待線程結(jié)束(當(dāng)然程序中是要讓線程無限循環(huán)的):
pthread_join(thrd,NULL);?
???? 當(dāng)面這些都實現(xiàn)以后,在Linux下編譯,生成目標(biāo)文件,下載到開發(fā)板準(zhǔn)備運行。
由于μClinux攜帶了RTL8019驅(qū)動和TCP/IP協(xié)議,因此,在μClinux下實現(xiàn)網(wǎng)絡(luò)功能就顯得比較的簡單。
服務(wù)器端的程序:
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)?????? //UDP方式
{
???? printf("ERROR:Cannot obtain Socket Descriptor!\n");
????????? return(0);
}
addr_local.sin_family=AF_INET;????????????????????
addr_local.sin_port=htons(PORT);
addr_local.sin_addr.s_addr=INADDR_ANY;
if(bind(sockfd,(struct sockaddr *)&addr_local,sizeof(struct sockaddr)) == -1)
{
printf("ERROR:Cannot bind port %d\n !",PORT);
return (0);
???????? }
else
???????? {
????????? printf("OK:Bind successfully!\n");
???????? }
sin_size=sizeof(struct sockaddr);
num=recvfrom( sockfd , revbuf , sizeof ( revbuf ) , 0 ,
( struct sockaddr* ) & addr_remote, &sin_size );
if(num<0)
{
???????? }
else
???????? {
write(fd,revbuf,num);
printf("\n");
}
?? 客戶端程序:
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)?????? //UDP方式
{
????? printf("ERROR:Cannot obtain Socket Descriptor!\n");
????????? return(0);
}
addr_remote.sin_family=AF_INET;
addr_remote.sin_port=htons(PORT);???????????????????
addr_remote.sin_addr.s_addr=inet_addr((const char*)m_strServer);
size=read(fd,revbuf,8);
if(size>0)
{
num=sendto(sockfd,revbuf,size,0,(struct sockaddr * )&addr_remote,sizeof(struct sockaddr_in));
if(num<0)
{
????????????????? printf("ERROR:Cannot send your data!\n");
}
else
??????????? {
???????????????? printf("OK,Sent Success");
??????????? }
}
在μClinux下的串口實現(xiàn),由于它已經(jīng)帶了串口的驅(qū)動程序,只需要在應(yīng)用的時候?qū)⑵浯蜷_就可以。這里,我們使用默認(rèn)的115200Hz的頻率,8位數(shù)據(jù)位,無奇偶校驗,1位停止位,無數(shù)據(jù)流控制。
代碼如下:
int fd;
fd=open("/dev/ttyS0",O_RDWR);
其中open函數(shù)表示打開設(shè)備文件,因為Linux是以文件方式管理設(shè)備的,要打開一個設(shè)備,只需要用打開文件的函數(shù)就可以了。而串口在Linux里位于dev文件夾下,串口0、串口1依次對應(yīng)ttyS0、ttyS1。O_RDWR表示以可讀寫方式打開設(shè)備。fd存儲設(shè)備號,如所有欲檢查的權(quán)限都通過了則返回0值,表示成功,只要有一個權(quán)限被禁止則返回-1。
同樣的,將數(shù)據(jù)寫入串口的話,我們使用write函數(shù):
int fd;
write(fd,buf,num);
這里fd表示已經(jīng)打開的設(shè)備號,這里是串口0,buf表示需要發(fā)送的數(shù)據(jù),而num則表示發(fā)送的數(shù)據(jù)量。如果發(fā)送失敗則返回-1,錯誤代碼寫人errno中。如果write順利,則返回實際寫入的字節(jié)數(shù)。
好了,上面的一些解釋介紹,下面的完整的源代碼:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT??????? 5000??????????? //通信端口
#define LENGTH????? 64????????????? //緩存大小
void task(int *counter);?????????? //task:ser2udp
void task2(int *counter);????????? //task2:udp2ser
int gCounter = 0;?????????????????
int gCounter2 = 0;
//task的變量
int size;
int sockfd;?????????????????????????
int num;????????????????????????????????
char revbuf[LENGTH];
//task2的變量
int size2;??????????????????????
int num2;?????????????????????????????
char revbuf2[LENGTH];
//變量
int fd;
char m_strServer[]="192.168.0.10";????? //PC的IP?
struct sockaddr_in addr_local;
struct sockaddr_in addr_remote;?
int main(void)
{
pthread_t thrd,thrd2;
int result;
//¥úo(TM)0
if((fd=open("/dev/ttyS0",O_RDWR))==-1)
{
printf("ERROR:can not open COM0\n");
return (0);
}
else
{
printf("Success open COM0\n");
}
//ser2udp
addr_remote.sin_family=AF_INET;??????? //UDP
addr_remote.sin_port=htons(PORT);????????????????? //填入端口
addr_remote.sin_addr.s_addr=inet_addr((const char*)m_strServer);?? //目標(biāo)IP
//udp2ser
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1)
{
??????? printf("ERROR:Cannot obtain Socket Descriptor!\n");
return(0);
??????? }
addr_local.sin_family=AF_INET;????????????????????
addr_local.sin_port=htons(PORT);?????????????????
addr_local.sin_addr.s_addr=INADDR_ANY;????????????
if(bind( sockfd,(struct sockaddr *)&addr_local,sizeof(struct sockaddr))==-1)
{
printf("ERROR:Cannot bind port %d\n !",PORT);
return (0);
}
else
{
printf("OK:Bind successfully!\n");
}
size2 = sizeof(struct sockaddr);
fprintf(stderr,"hello world\n");
//創(chuàng)建task
result = pthread_create(&thrd,NULL,(void*)task,(void*)&gCounter);????
if (result)
{
perror("pthread create fail");
exit(0);
}
//創(chuàng)建task2
result = pthread_create(&thrd2,NULL,(void*)task2,(void*)&gCounter2);?
if (result)
{
perror("pthread create fail");
exit(0);
}
pthread_join(thrd,NULL);???????? //等待task結(jié)束
return 0;
}
//?flser2udp
void task(int *counter)
{
printf("hello world from pthread1!\n");
while(1)
{
??????? size=read(fd,revbuf,8);???????????? //從串口讀取數(shù)據(jù)
??????? if(size>0)????????????????????????? //size里是讀取到的數(shù)據(jù)量
{?
?????????????? //發(fā)向網(wǎng)絡(luò)
num=sendto(sockfd,revbuf,size,0,
(struct sockaddr * )&addr_remote,sizeof(struct sockaddr_in));???
?????????????? //發(fā)送失敗
if(num<0)??????????????????????????????????????????
{
??????? printf("ERROR:Cannot send your dta!\n");
??????? }
else
??????? {
??????? }
}
}
}
//task2:udp2ser
void task2(int *counter)
{
printf("hello world from pthread2!\n");
while(1)
{?
//等待網(wǎng)絡(luò)數(shù)據(jù)
num2=recvfrom(sockfd,revbuf2,sizeof(revbuf2),0,
(struct sockaddr * )&addr_remote,&size2);?
if(num2<0)??????????????????? //獲取失敗??????????????????
{
}
else???????????????????????????????????????????????
{
write(fd,revbuf2,num2);????? //寫入串口
printf("\n");
}
}
}
好了,按照上面的步驟編譯運行,然后同時打開SSCOM3.2和網(wǎng)絡(luò)調(diào)試助手,都設(shè)置成定時發(fā)送模式,我都設(shè)置成10ms,二者不斷發(fā)送接收數(shù)據(jù),測試了一下,在一個局域網(wǎng)內(nèi),數(shù)據(jù)的丟失量的非常小的。
總結(jié)
以上是生活随笔為你收集整理的uclinux多线程应用-网络通信[转]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自制超声波驱狗器(第三版)
- 下一篇: 小白都能看懂 XAMPP的下载安装配置详