socket(套接字)详解一种通讯机制
socket給提供給使用進(jìn)程TCP/UDP等網(wǎng)絡(luò)協(xié)議進(jìn)行網(wǎng)絡(luò)通訊手段。
linux中網(wǎng)絡(luò)編程通過socket接口實(shí)現(xiàn);
socket既是一種特殊的IO,提供對應(yīng)的文件描述符。socket都有一個(gè)相關(guān)的描述{協(xié)議,本地地址,本地端口,遠(yuǎn)程地址,遠(yuǎn)程端口}(五元組信息);每一個(gè)socket有一個(gè)本地的唯一socket,由操作系統(tǒng)分配。
| socket說到底就是一個(gè)結(jié)構(gòu)體 |
socket創(chuàng)建在內(nèi)核中,若創(chuàng)建成功返回文件描述表中的socket描述符;
使用socket內(nèi)核調(diào)用,創(chuàng)建結(jié)構(gòu)體;
socket函數(shù)對應(yīng)于普通文件的打開操作。普通文件的打開操作返回一個(gè)文件描述字,而socket()用于創(chuàng)建一個(gè)socket描述符(socket descriptor),它唯一標(biāo)識一個(gè)socket。這個(gè)socket描述字跟文件描述字一樣,后續(xù)的操作都有用到它,把它作為參數(shù),通過它來進(jìn)行一些讀寫操作。
正如可以給fopen的傳入不同參數(shù)值,以打開不同的文件。創(chuàng)建socket的時(shí)候,也可以指定不同的參數(shù)創(chuàng)建不同的socket描述符,socket函數(shù)的三個(gè)參數(shù)分別為:
domain:即協(xié)議域,又稱為協(xié)議族(family)。常用的協(xié)議族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或稱AF_UNIX,Unix域socket)、AF_ROUTE等等。協(xié)議族決定了socket的地址類型,在通信中必須采用對應(yīng)的地址,如AF_INET決定了要用ipv4地址(32位的)與端口號(16位的)的組合、AF_UNIX決定了要用一個(gè)絕對路徑名作為地址。
type:指定socket類型。常用的socket類型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等
protocol:就是指定協(xié)議。常用的協(xié)議有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它們分別對應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議、TIPC傳輸協(xié)議。protocol一般取為0,表示給定的域和套接字類型類型選擇默認(rèn)協(xié)議;
注意:并不是上面的type和protocol可以隨意組合的,如SOCK_STREAM不可以跟IPPROTO_UDP組合。當(dāng)protocol為0時(shí),會自動選擇type類型對應(yīng)的默認(rèn)協(xié)議。
| Socket編程實(shí)例 |
服務(wù)器端:一直監(jiān)聽本機(jī)的8000號端口,如果收到連接請求,將接收請求并接收客戶端發(fā)來的消息,并向客戶端返回消息
/* File Name: server.c */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define DEFAULT_PORT 8000 #define MAXLINE 4096 int main(int argc, char** argv) { int socket_fd, connect_fd; struct sockaddr_in servaddr; char buff[4096]; int n; //初始化Socket if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } //初始化 memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址設(shè)置成INADDR_ANY,讓系統(tǒng)自動獲取本機(jī)的IP地址。 servaddr.sin_port = htons(DEFAULT_PORT);//設(shè)置的端口為DEFAULT_PORT //將本地地址綁定到所創(chuàng)建的套接字上 if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } //開始監(jiān)聽是否有客戶端連接 if( listen(socket_fd, 10) == -1){ printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("======waiting for client's request======\n"); while(1){ //阻塞直到有客戶端連接,不然多浪費(fèi)CPU資源。 if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){ printf("accept socket error: %s(errno: %d)",strerror(errno),errno); continue; } //接受客戶端傳過來的數(shù)據(jù) n = recv(connect_fd, buff, MAXLINE, 0); //向客戶端發(fā)送回應(yīng)數(shù)據(jù) if(!fork()){ /*紫禁城*/ if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1) perror("send error"); close(connect_fd); exit(0); } buff[n] = '\0'; printf("recv msg from client: %s\n", buff); close(connect_fd); } close(socket_fd); }客戶端:
/* File Name: client.c */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define MAXLINE 4096 int main(int argc, char** argv) { int sockfd, n,rec_len; char recvline[4096], sendline[4096]; char buf[MAXLINE]; struct sockaddr_in servaddr; if( argc != 2){ printf("usage: ./client <ipaddress>\n"); exit(0); } if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8000); if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ printf("inet_pton error for %s\n",argv[1]); exit(0); } if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ printf("connect error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("send msg to server: \n"); fgets(sendline, 4096, stdin); if( send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); exit(0); } if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) { perror("recv error"); exit(1); } buf[rec_len] = '\0'; printf("Received : %s ",buf); close(sockfd); exit(0); }代碼原文地址
總結(jié)
以上是生活随笔為你收集整理的socket(套接字)详解一种通讯机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 作者:金海,博士,华中科技大学计算机科学
- 下一篇: sockaddr与 sockaddr_i