Linux學習之網路程式設計(TCP程式設計)
阿新 • • 發佈:2018-11-15
言之者無罪,聞之者足以戒。 - “詩序”
1,TCP是什麼?
TCP傳輸控制協議
向用戶程序提供可靠的全雙工位元組流(位元組流:給每一個位元組編序)
2,UDP是什麼?
UDP使用者資料報協議
是一種無連線的協議
3,獲取時間服務的客戶端
(1),建立一個的的IPv4(AF_INET)的位元組流(SOCK_STREAM)套接字
(2),連線到IP地址,埠號為8888的伺服器
(3),寫一個數據到伺服器
(4),接收伺服器傳回來的資料並顯示到標準輸出
(5),關閉套接字
下面來看一下客戶端的程式:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <fcntl.h> int main(int argc,char *argv[]) { int sockfd; struct sockaddr_in servaddr; char buf[100];//儲存讀取的內容 int bytes;//儲存讀取的位元組數 if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)//建立套接字 { printf("socket error\n"); return -1; } //結構體中成員變數初始化為0 bzero(&servaddr,sizeof(servaddr)); //初始化成員變數 servaddr.sin_family = AF_INET;//IPv4 servaddr.sin_addr.s_addr = inet_addr("192.168.177.133");//轉換為地址格式 servaddr.sin_port = htons(8888);//主機序轉換到網路序 //連線伺服器 if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0)//繫結伺服器ip和埠到>套結字 { perror("connect error"); return -2; } //儲存讀取的資料和讀取的位元組數 bytes == read(sockfd,buf,100); if(bytes < 0) { printf("Error ,read failed\n"); return -3; } //如果讀取的位元組數為0 ,就說明連線已經關閉了 if(0 == bytes) { printf("Server close connection\n"); return -4; } //列印讀取的位元組數和讀取的內容 printf("read bytes %d\n",bytes); printf("Time: %s\n",buf); //關閉套結字 close(sockfd); return 0; }
上面的程式的設計思路已經說了,我也在程式中寫了必要的註釋,相信是比較容易接受。
如圖4所示,提供時間的伺服器端:
(1),繫結已知的IPv4的的的的地址(INADDR_ANY)和埠號(8888)
(2),將套接字轉換成監聽套接字
(3),睡眠等待客戶端連線
(4),讀取客戶端資料
(5),將收到的資料傳送給客戶端
(6),睡眠1S後關閉套接字
接下來看一下伺服器的程式:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <fcntl.h> #define MAX_LISTEN_QUE 5 int main(int argc,char *argv[]) { int listenfd,sockfd,opt=1;//listenfd建立的普通套接字,sockfd通訊套接字 struct sockaddr_in server,client; char buf[200]; socklen_t len; int timep; int ret; //建立套接字 listenfd = socket(AF_INET,SOCK_STREAM,0); if(listenfd < 0) { perror("Create socket fail"); return -1; //設定套結字關聯的選項(設定地址的重用) if((ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0) { perror("Error ,set socket reuse addr failed"); return -1; } //清空結構體中的變數值 bzero(&server, sizeof(server)); //初始化結構體的變數 server.sin_family = AF_INET;//IPv4 server.sin_port = htons(8888);//主機轉換到網路 server.sin_addr.s_addr = htonl(INADDR_ANY);//同上(使用這個巨集套接字可以繫結到所有的端>口) //獲取結構體地址長度 len = sizeof(struct sockaddr); //繫結伺服器ip地址和埠到套接字 if(bind(listenfd, (struct sockaddr *)&server, len)<0) { perror("bind error."); return -1; } //設定伺服器的最大連線數 listen(listenfd, MAX_LISTEN_QUE); //迭代(就是可以有多個客戶端只是不能同時通訊) while(1) { //等待客戶端請求,如果請求到來,返回一個新的socket //伺服器和客戶端利用新的socket來通訊 sockfd = accept(listenfd, (struct sockaddr *)&client, &len); if(sockfd < 0) { perror("accept error."); return -1; } //顯示系統的當前時間 timep = time(NULL); //將資料按照一定的格式轉換之後複製到buf //ctime返回一個表示當地時間的字串 snprintf(buf, sizeof(buf), "%s", ctime(&timep)); //向套接字中寫入buf儲存的時間 write(sockfd, buf, strlen(buf)); //列印儲存的位元組數 printf("Bytes:%d\n", strlen(buf)); //列印套接字的檔案描述符 printf("sockfd=%d\n", sockfd); //關閉套接字 close(sockfd); } return 0; }