Linux下TCP網(wǎng)絡(luò)編程-創(chuàng)建服務(wù)器與客戶端
一、前言
互聯(lián)網(wǎng)概念誕生于20世紀(jì)60年代末,從9幾年中國(guó)接入互聯(lián)網(wǎng)開(kāi)始到現(xiàn)在,生活的每個(gè)角落都能看到網(wǎng)絡(luò)的使用?,F(xiàn)在物聯(lián)網(wǎng)時(shí)代、共享經(jīng)濟(jì)的到來(lái),生活中不僅僅電腦、手機(jī)可以接入網(wǎng)絡(luò),身邊的各個(gè)設(shè)備也能接入互聯(lián)網(wǎng)了。 比如:市政路燈、污水井蓋、家用電器,汽車(chē)等等。
這篇文章介紹在Linux下的socket編程,完成TCP服務(wù)器、客戶端的創(chuàng)建,實(shí)現(xiàn)數(shù)據(jù)通信。
二、TCP協(xié)議介紹
在Linux應(yīng)用層做編程,接觸到是傳輸層協(xié)議,TCP/UDP,如果搞Linux網(wǎng)絡(luò)驅(qū)動(dòng)開(kāi)發(fā)(網(wǎng)卡驅(qū)動(dòng)),那么底層的網(wǎng)絡(luò)協(xié)議就會(huì)接觸的更多,協(xié)議只是一個(gè)數(shù)據(jù)格式的約定而已,自己也可以設(shè)計(jì)自己的協(xié)議。
下面這張圖介紹兩個(gè)設(shè)備通過(guò)網(wǎng)絡(luò)通信的一個(gè)大致流程:
TCP協(xié)議是點(diǎn)對(duì)點(diǎn)傳輸協(xié)議。TCP協(xié)議屬于C/S模型。
TCP協(xié)議里包含服務(wù)器和客戶端。
服務(wù)器必須要比客戶端先存在,客戶端必須連接服務(wù)器,服務(wù)器必須被客戶端連接。
接下來(lái)學(xué)習(xí)主要學(xué)習(xí)TCP服務(wù)器創(chuàng)建和TCP客戶端創(chuàng)建,完成客戶端與服務(wù)器之間的通信。
TCP服務(wù)器可以被多個(gè)客戶端連接。
Linux下socket編程需要用到的相關(guān)函數(shù):
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int socket(int domain, int type, int protocol);
AF_UNIX, AF_LOCAL Local communication unix(7) AF_INET IPv4 Internet protocols ip(7) AF_INET6 IPv6 Internet protocols ipv6(7) AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device netlink(7) AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7) AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK AppleTalk ddp(7) AF_PACKET Low level packet interface packet(7) AF_ALG Interface to kernel crypto API #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); struct sockaddr { sa_family_t sa_family; char sa_data[14];
} #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); #define _GNU_SOURCE /* See feature_test_macros(7) */ #include <sys/socket.h> int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
三、案例代碼
3.1 創(chuàng)建TCP服務(wù)器
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> /*
TCP服務(wù)器創(chuàng)建步驟:
1. 創(chuàng)建socket套接字(類似于open打開(kāi)文件一樣)
2. 綁定端口號(hào)和IP地址
3. 設(shè)置監(jiān)聽(tīng)等待隊(duì)列的數(shù)量
4. 等待客戶端連接
5. 完成正常數(shù)據(jù)收發(fā)
0x1234
192.168.1.123
255.255.255.255
*/ int main(int argc,char **argv) { if(argc!=2)
{ printf("./app <端口號(hào)>\n"); return 0;
} int sockfd; /*1. 創(chuàng)建socket套接字*/ sockfd=socket(AF_INET,SOCK_STREAM,0); /*2. 綁定端口號(hào)與IP地址*/ struct sockaddr_in addr; addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[1])); // 端口號(hào)0~65535 addr.sin_addr.s_addr=INADDR_ANY; //inet_addr("0.0.0.0"); //IP地址 if(bind(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr))!=0)
{ printf("服務(wù)器:端口號(hào)綁定失敗.\n");
} /*3. 設(shè)置監(jiān)聽(tīng)的數(shù)量*/ listen(sockfd,20); /*4. 等待客戶端連接*/ int client_fd; struct sockaddr_in client_addr; socklen_t addrlen=sizeof(struct sockaddr_in);
client_fd=accept(sockfd, (struct sockaddr *)&client_addr,&addrlen); if(client_fd<0)
{ printf("客戶端連接失敗.\n"); return 0;
} printf("連接的客戶端IP地址:%s\n",inet_ntoa(client_addr.sin_addr)); printf("連接的客戶端端口號(hào):%d\n",ntohs(client_addr.sin_port)); /*5. 完成通信*/ write(client_fd,"1234567890",10); /*6. 關(guān)閉連接*/ close(client_fd);
close(sockfd); return 0;
}
3.2 創(chuàng)建TCP客戶端
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> /*
TCP客戶端創(chuàng)建步驟:
1. 創(chuàng)建socket套接字(類似于open打開(kāi)文件一樣)
2. 連接服務(wù)器
3. 完成正常數(shù)據(jù)收發(fā)
*/ int main(int argc,char **argv) { if(argc!=3)
{ printf("./app <IP地址> <端口號(hào)>\n"); return 0;
} int sockfd; /*1. 創(chuàng)建socket套接字*/ sockfd=socket(AF_INET,SOCK_STREAM,0); /*2. 連接服務(wù)器*/ struct sockaddr_in addr; addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(argv[2])); // 端口號(hào)0~65535 addr.sin_addr.s_addr=inet_addr(argv[1]); //IP地址 if(connect(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr_in))!=0)
{ printf("客戶端:服務(wù)器連接失敗.\n"); return 0;
} /*3. 完成數(shù)據(jù)通信*/ char buff[1024]; int cnt;
cnt=read(sockfd,buff,1024);
buff[cnt]='\0'; printf("客戶端收到的數(shù)據(jù):%s,%d\n",buff,cnt);
close(sockfd); return 0;
}