基于Socket實現(xiàn)一對一通信1_第1頁
基于Socket實現(xiàn)一對一通信1_第2頁
基于Socket實現(xiàn)一對一通信1_第3頁
基于Socket實現(xiàn)一對一通信1_第4頁
基于Socket實現(xiàn)一對一通信1_第5頁
已閱讀5頁,還剩12頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、Linux下的Socket編程實現(xiàn)一對一通信 田昕煜 (1.通信工程,13081405)摘要: 以當(dāng)下社會普遍應(yīng)用QQ,微信,微博等聊天工具為引,設(shè)計了簡單的Linux系統(tǒng)下的socket編程實現(xiàn)客戶端與服務(wù)器的一對一通信。關(guān)鍵詞: 多線程,socket創(chuàng)建,bind函數(shù),connect函數(shù),listen函數(shù),accept函數(shù),數(shù)據(jù)傳輸0 基本原理本聊天室程序在 Ubuntu 下,采用 C 語言實現(xiàn),結(jié)構(gòu)為 Client/Server 結(jié)構(gòu);服務(wù)端程序通過共享存儲區(qū)存儲聊天數(shù)據(jù),并發(fā)送給每個連接的客戶端;服務(wù)端程序和客戶端程序都是通過父子進程分別負責(zé)發(fā)送和接收數(shù)據(jù)的,以避免數(shù)據(jù)沖撞;1設(shè)計思路

2、及功能1.1 總體設(shè)計框架1.2程序設(shè)計方案Socket創(chuàng)建 socket函數(shù)原型為: #include #include int socket(int domain, int type, int protocol); 功能:調(diào)用成功,返回socket文件描述符;失敗,返回1,并設(shè)置errno 參數(shù)說明: domain指明所使用的協(xié)議族,通常為PF_INET,表示互聯(lián)網(wǎng)協(xié)議族(TCP/IP協(xié)議 族; type參數(shù)指定socket的類型: SOCK_STREAM 提供有序、可靠、雙向及基于連接的字節(jié)流 SOCK_DGRAM 支持?jǐn)?shù)據(jù)報 SOCK_SEQPACKET 提供有序、可靠、雙向及基于連接

3、的數(shù)據(jù)報通信 SOCK_RAW 提供對原始網(wǎng)絡(luò)協(xié)議的訪問 SOCK_RDM 提供可靠的數(shù)據(jù)報層,但是不保證有序性 protocol通常賦值0. socket描述符是一個指向內(nèi)部數(shù)據(jù)結(jié)構(gòu)的指針,它指向描述符表入口。調(diào)用socket函數(shù)時,socket執(zhí)行體將建立一個socket,實際上建立一個socket意味著為一個socket數(shù)據(jù)結(jié)構(gòu)分配存儲空間。socket執(zhí)行體為你管理描述符表。 兩個網(wǎng)絡(luò)程序之間的一個網(wǎng)絡(luò)連接包括五種信息:通信協(xié)議、本地協(xié)議地址、本地主機端口、遠端主機地址和遠端協(xié)議端口。socket數(shù)據(jù)結(jié)構(gòu)中包含這五種信息。Socket綁定 bind函數(shù)原型為: #include #in

4、clude int bind(int sock_fd,struct sockaddr *my_addr, int addrlen); 功能說明:將套接字和指定的端口相連。成功返回0,否則,返回1,并置errno. 參數(shù)說明:sock_fd是調(diào)用socket函數(shù)返回的socket描述符, my_addr是一個指向包含有本機IP地址及端口號等信息的sockaddr類型的指針; addrlen常被設(shè)置為sizeof(struct sockaddr)。 struct sockaddr結(jié)構(gòu)類型是用來保存socket信息的: struct sockaddr unsigned short sa_family

5、; /* 地址族, AF_xxx */ char sa_data14; /* 14 字節(jié)的協(xié)議地址 */ ; sa_family一般為AF_INET,代表Internet(TCP/IP)地址族; sa_data則包含該socket的IP地址和端口號。 另外還有一種結(jié)構(gòu)類型: struct sockaddr_in short int sin_family; /* 地址族 */ unsigned short int sin_port; /* 端口號 */ struct in_addr sin_addr; /* IP地址 */ unsigned char sin_zero8; /* 填充0 以保持與

6、struct sockaddr同樣大小 */ ; 這個結(jié)構(gòu)更方便使用。sin_zero用來將sockaddr_in結(jié)構(gòu)填充到與struct sockaddr同樣的長度,可以用bzero()或memset()函數(shù)將其置為零。指向sockaddr_in 的指針和指向sockaddr的指針可以相互轉(zhuǎn)換,這意味著如果一個函數(shù)所需參數(shù)類型是sockaddr時,你可以在函數(shù)調(diào)用的時候?qū)⒁粋€指向 sockaddr_in的指針轉(zhuǎn)換為指向sockaddr的指針;或者相反。 使用bind函數(shù)時,可以用下面的賦值實現(xiàn)自動獲得本機IP地址和隨機獲取一個沒有被占用的端口號: my_addr.sin_port = 0;

7、/* 系統(tǒng)隨機選擇一個未被使用的端口號 */ my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本機IP地址 */ 通過將my_addr.sin_port置為0,函數(shù)會自動為你選擇一個未占用的端口來使用。同樣,通過將my_addr.sin_addr.s_addr置為INADDR_ANY,系統(tǒng)會自動填入本機IP地址。 注意在使用bind函數(shù)是需要將sin_port和sin_addr轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)優(yōu)先順序。 計算機數(shù)據(jù)存儲有兩種字節(jié)優(yōu)先順序:高位字節(jié)優(yōu)先和低位字節(jié)優(yōu)先(大端和小端)。Internet上數(shù)據(jù)以高位字節(jié)優(yōu)先順序在網(wǎng)絡(luò)上傳輸,所以對于在內(nèi)部是以低位字

8、節(jié)優(yōu)先方式存儲數(shù)據(jù)的機器,在Internet上傳輸數(shù)據(jù)時就需要進行轉(zhuǎn)換,否則就會出現(xiàn)數(shù)據(jù)不一致。 Bind()函數(shù)在成功被調(diào)用時返回0;出現(xiàn)錯誤時返回-1并將errno置為相應(yīng)的錯誤號。 需要注意的是,在調(diào)用bind函數(shù)時一般不要將端口號置為小于1024的值,因為1到1024是保留端口號,你可以選擇大于1024中的任何一個沒有被占用的端口號。連接 面向連接的客戶程序使用connect函數(shù)來配置socket并與遠端服務(wù)器建立一個TCP連接,其函數(shù)原型為: #include #include int connect(int sock_fd, struct sockaddr *serv_addr,i

9、nt addrlen); 功能說明:客戶端發(fā)送服務(wù)請求。成功返回0,否則返回1,并置errno。 參數(shù)說明:sock_fd 是socket函數(shù)返回的socket描述符;serv_addr是包含遠端主機IP地址和端口號的指針;addrlen是遠端地質(zhì)結(jié)構(gòu)的長度。 進行客戶端程序設(shè)計無須調(diào)用bind(),因為這種情況下只需知道目的機器的IP地址,而客戶通過哪個端口與服務(wù)器建立連接并不需要關(guān)心, socket執(zhí)行體為你的程序自動選擇一個未被占用的端口,并通知你的程序數(shù)據(jù)什么時候到端口。 connect函數(shù)啟動和遠端主機的直接連接。只有面向連接的客戶程序使用socket時才需要將此socket與遠端主

10、機相連。無連接協(xié)議從不建立直接連接。面向連接的服務(wù)器也從不啟動一個連接,它只是被動的在協(xié)議端口監(jiān)聽客戶的請求。監(jiān)聽 listen函數(shù)使socket處于被動的監(jiān)聽模式,并為該socket建立一個輸入數(shù)據(jù)隊列,將到達的服務(wù)請求保存在此隊列中,直到程序處理它們。 int listen(int sock_fd, int backlog); 功能說明:等待指定的端口的出現(xiàn)客戶端連接。調(diào)用成功返回0,否則,返回1,并置errno. 參數(shù)說明:sock_fd 是socket系統(tǒng)調(diào)用返回的socket 描述符; backlog指定在請求隊列中允許的最大請求數(shù),進入的連接請求將在隊列中等待accept()接受

11、accept()函數(shù)讓服務(wù)器接收客戶的連接請求。在建立好輸入隊列后,服務(wù)器就調(diào)用accept函數(shù),然后睡眠并等待客戶的連接請求。 int accept(int sock_fd, void *addr, int *addrlen); 功能說明:用于接受客戶端的服務(wù)請求,成功返回新的套接字描述符,失敗返回1,并置errno。 參數(shù)說明:sock_fd是被監(jiān)聽的socket描述符,addr通常是一個指向sockaddr_in變量的指針,該變量用來存放提出連接請求服務(wù)的主機的信息(某臺主機從某個端口發(fā)出該請求);addrten通常為一個指向值為sizeof(struct sockaddr_in)的整型

12、指針變量。出現(xiàn)錯誤時accept函數(shù)返回-1并置相應(yīng)的errno值。 首先,當(dāng)accept函數(shù)監(jiān)視的 socket收到連接請求時,socket執(zhí)行體將建立一個新的socket,執(zhí)行體將這個新socket和請求連接進程的地址聯(lián)系起來,收到服務(wù)請求的初始socket仍可以繼續(xù)在以前的 socket上監(jiān)聽,同時可以在新的socket描述符上進行數(shù)據(jù)傳輸操作。結(jié)束傳輸 當(dāng)所有的數(shù)據(jù)操作結(jié)束以后,你可以調(diào)用close()函數(shù)來釋放該socket,從而停止在該socket上的任何數(shù)據(jù)操作: 2關(guān)鍵代碼解釋客戶端: #include #include #include #include #include #

13、include #include #define LISTEN_LEN 10int err,sd;char rd_buf100, wr_buf100;void *thread_read1(void *arg)while(1)memset(rd_buf,0,100);read(sd,rd_buf,100);printf(%sn,rd_buf);sleep(2);return NULL;void *thread_write1(void *arg)while(1)memset(wr_buf, 0, 100);scanf(%s, wr_buf);write(sd,wr_buf,sizeof(wr_bu

14、f);sleep(2);return NULL;int main()pthread_t tid1,tid2;int server_len,client_len;struct sockaddr_in server_ip,client_ip;sd = socket(AF_INET,SOCK_STREAM,0);if(sd 0)printf(socket failed! errno = %dn,errno);close(sd);return -1;server_ip.sin_family = AF_INET;server_ip.sin_port = htons(5678);server_ip.sin

15、_addr.s_addr = htonl(INADDR_ANY);memset(server_ip.sin_zero,0,8); err = connect(sd,(struct sockaddr *)(&server_ip),sizeof(struct sockaddr);if(err 0)printf(connect failed! errno = %dn,errno);close(sd);return -1;err = pthread_create(&tid1,NULL,thread_read1,NULL);if(err != 0)printf(thread_read1 creat fa

16、iled! errno = %dn,errno);close(sd);return -1;err = pthread_create(&tid2,NULL,thread_write1,NULL);if(err != 0)printf(thread_write1 creat failed! errno = %dn,errno);close(sd);return -1;pthread_join(tid1,NULL);pthread_join(tid2,NULL);close(sd);return 0 ; 服務(wù)器:#include #include #include #include #include

17、 #include #include #define LISTEN_LEN 10int i=0,err,sd,ad;char buf12100,buf21100;void *thread_read1(void *arg);void *thread_write1(void *arg);void *thread_read1(void *arg)while(1)read(ad,buf12,100);printf(%sn, buf12);sleep(2);return NULL;void *thread_write1(void *arg)while(1)memset(buf21, 0, 100);sc

18、anf(%s, buf21);write(ad,buf21,100);sleep(2);return NULL;int main()pthread_t tid1,tid2;int server_len,client_len;struct sockaddr_in server_ip,client_ip;sd = socket(AF_INET,SOCK_STREAM,0);if(sd 0)printf(socket failed! errno = %dn,errno);close(sd);return -1;server_ip.sin_family = AF_INET;server_ip.sin_

19、port = htons(5678);server_ip.sin_addr.s_addr = htonl(INADDR_ANY);memset(server_ip.sin_zero,0,8); err = bind(sd,(struct sockaddr *)(&server_ip),sizeof(struct sockaddr);if(err 0)printf(bind failed! errno = %dn,errno);close(sd);return -1;err = listen(sd,LISTEN_LEN);if(err 0)printf(listen failed! errno

20、= %dn,errno);close(sd);return -1;client_len = sizeof(struct sockaddr);while(1)ad = accept(sd,(struct sockaddr *)(&client_ip),&client_len);if(ad 0 )printf(accept failed! errno = %dn,errno);close(sd);return -1;err = pthread_create(&tid1,NULL,thread_read1,NULL);if(err != 0)printf(thread_read1 creat failed! errno = %dn,errno);close(sd);close(ad);return -1;err = pthread_create(&tid2,NULL,thread_write1,NULL);if(err != 0)printf(thread_write1 creat f

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論