Linux C : TCP/IP 和 网络编程
目錄
一、IP主機和IP地址
二、IP數(shù)據(jù)包格式
三、TCP/IP在網(wǎng)絡(luò)中的數(shù)據(jù)流
四、套接字編程
4.1 創(chuàng)建套接字
4.2綁定socket和端口號?
4.3、UDP 套接字
4.4 TCP 套接字
?五、 UDP回顯? 服務(wù)器-客戶機程序
六、TCP 回顯服務(wù)器-客戶機
?TCP/IP 是互聯(lián)網(wǎng)的基礎(chǔ), TCP代表傳輸控制協(xié)議,IP代表互聯(lián)網(wǎng)協(xié)議。目前有兩個版本IP,一個是32位地址的IPv4 和一個是128位的 IPv6 。而IPv4 是現(xiàn)如今使用最多的IP版本,也是這次討論的重點。
一、IP主機和IP地址
? ? ? 每一個注意由一個32位的IP地址來標識。為了方便起見,通常用32位的IP低質(zhì)號用記點法標識例如:134.121.64.1? 也可以用主機名標識如 dns1.eec.wsu.edu 。實際上應(yīng)用程序通常使用主機名而不是IP地址。因為給定其中一個,我們都可以通過dns(域名系統(tǒng))服務(wù)器找到另外一個,兩者之間可以相互轉(zhuǎn)換。
? ? ? IP地址分為兩部分 NeiworkID 和 HostID 字段。其中,IP 可以分為A~E類。例如B類IP分為一個16位NeiworkID,前兩位是10 。發(fā)往UP地址的數(shù)據(jù)包首先被發(fā)送到具有相同networkID的路由器默認IP地址位127.0.0.1.
二、IP數(shù)據(jù)包格式
IP數(shù)據(jù)包由IP頭、發(fā)送方IP地址、接收方IP地址和數(shù)據(jù)組成。每個IP數(shù)據(jù)包的大小最大為64K。IP頭包含有關(guān)數(shù)據(jù)包的信息。內(nèi)容如下:? ?
?IP主機可能距離很遠通常不可能從一個主機直接向另一個主機發(fā)送數(shù)據(jù)包。路由器是轉(zhuǎn)發(fā)數(shù)據(jù)包的特殊IP主機,它可以向普通IP主機和其他路由器發(fā)送數(shù)據(jù)包,
三、TCP/IP在網(wǎng)絡(luò)中的數(shù)據(jù)流
?應(yīng)用層的數(shù)據(jù)被傳到傳輸層會添加TCP 或者UDP包頭來標識使用的傳輸協(xié)議。合并后的數(shù)據(jù)被傳到IP網(wǎng)絡(luò)層,添加一個包含IP地址的IP報頭來標識發(fā)送和接收主機。然后合并后的數(shù)據(jù)傳遞到網(wǎng)絡(luò)鏈路層,再次將數(shù)據(jù)分成多個幀,添加發(fā)送和接收網(wǎng)絡(luò)的地址,用于在物理網(wǎng)絡(luò)之間的傳輸。
四、套接字編程
在 netdb.h 和 sys/socket.h中有套接字的地址結(jié)構(gòu)定義
struct sockaddr_in {sa_family_t sin_family; //TCP/IP網(wǎng)絡(luò)的sin_family 始終設(shè)置為AF_INETin_port_t sin_port; //包含網(wǎng)絡(luò)字節(jié)順序排列的端口號struct in_addr sin_addr ; //按網(wǎng)絡(luò)字節(jié)順序排列的IP地址 }struct in_addr{ unit32_t s_addr; //按網(wǎng)絡(luò)字節(jié)順序排列的IP地址 }服務(wù)器套接字編程步驟如下
客戶端套接字編程步驟如下
4.1 創(chuàng)建套接字
int socket(int domain, int type, int protocol);| AF_INET | IPv4協(xié)議 |
| AF_INET6 | Ipv6協(xié)議 |
| AF_LOCAL | Unix協(xié)議域/只在本機內(nèi)通信的套接字 |
| AF_ROUTE | 路由套接字 |
| AF_KEY | 秘鑰套接字 |
| SOCK_STREAM | 字節(jié)流套接字 (TCP) |
| SOCK_DGRAM | 數(shù)據(jù)報套接字 (UDP) |
| SOCK_SEQPACKET | 有序分組套接字 |
| SOCK_RAW | 原始套接字 |
4.2綁定socket和端口號?
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);?bind系統(tǒng)調(diào)用將addr指定的地址分配文件描述符 sockfd所引用的套接字,addrlen指定addr所指向地址結(jié)構(gòu)的大小對于用于聯(lián)系其他UDP服務(wù)器主機的UDP套接字,必須綁定到客戶機地址,允許服務(wù)器發(fā)回應(yīng)答。對于接收客戶機的TCP套接字,必須先將其綁定到服務(wù)器主機地址。
4.3、UDP 套接字
? ?將緩沖區(qū)中l(wèi)en字節(jié)數(shù)據(jù)發(fā)送到dest_addr標識的目標主機
ssize_t sendto(int fd, const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t tolen);? ?從緩沖區(qū)中l(wèi)en字節(jié)數(shù)接收數(shù)據(jù)
ssize_t recvfrom(int fd, void *buf, size_t len,int flags,struct sockaddr *src_addr, socklen_t *len);4.4 TCP 套接字
? 在綁定socket 和端口號后? TCP服務(wù)器用 listen 和 accpet 來監(jiān)聽、接受客戶機的連接
//backlog 定義了等待連接的最大長度 int listen(int sockfd, int backlog);//提取等待連接隊列上的第一個連接請求同于監(jiān)聽sockfd,執(zhí)行時造成進程阻塞,直到客戶機通過connect建立連接 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); // 返回新的文件描述符//如果sockfd 時SOCK_DGRAM (USD 套接字)類型時,addr時發(fā)送數(shù)據(jù)報的默認地址,也是接收數(shù)據(jù)報的唯一地址。如果時 SOCK_STREAM (TCP 套接字)類型時,connect連接到綁定到addr指定的套接字 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);發(fā)送/接收數(shù)據(jù)
? ? 可以使用? send/read? ?或者 recv/write? 來接收和發(fā)送數(shù)據(jù)。
read 和 write? 是對文件描述符的讀取和寫入
//對已經(jīng)連接的fd 發(fā)送數(shù)據(jù) ,flags 通常是0 ssize_t send(int fd , const void *buf , size_t len , int flags);//對已經(jīng)連接的fd 接收數(shù)據(jù) ,flags 通常是0 ssize_t recv(int fd , void *buf , size_t len , int flags);?五、 UDP回顯? 服務(wù)器-客戶機程序
? ?服務(wù)器端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>#define BUFLEN 256 #define PORT 1234char line[BUFLEN]; struct sockaddr_in me ,client; int sock ,rlen=sizeof(client); socklen_t clen = sizeof (client);int main (){printf("1. create a UDP socket\n");sock = socket (AF_INET,SOCK_DGRAM,IPPROTO_UDP);printf("2. fill me with server address and port number \n");memset((char *) & me ,0,sizeof(me));me.sin_family = AF_INET;me.sin_port = htons(PORT);me.sin_addr.s_addr = htonl(INADDR_ANY);printf("3. bind socket to server IP and port \n");bind (sock ,(struct sockaddr *) & me ,sizeof (me));printf("4. wait for datagram \n");while (1){memset(line ,0,BUFLEN);printf("UDP server:waiting for datagram \n");rlen =recvfrom (sock , line , BUFLEN,0,(struct sockaddr *)&client ,&clen);printf("received a datagram from [host : prot] =[%s :%d] \n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));printf("rlen=%d:line%s \n",rlen,line);printf("send reply \n");sendto (sock ,line,rlen,0,(struct sockaddr*)&client,clen);printf("------------------------\n");}}UDP客戶機端
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>#define BUFLEN 256 #define SERVER_PORT 1234 #define SERVER_HOST "127.0.0.1" char line[BUFLEN]; struct sockaddr_in server; int sock ,rlen,slen = sizeof (server);int main (){printf("1. create a UDP socket\n");sock = socket (AF_INET,SOCK_DGRAM,IPPROTO_UDP);printf("2. fill in server address and port number \n");memset((char *) & server ,0,sizeif(server));server.sin_family = AF_INET;server.sin_port = htons(SERVER_PORT);inet_aton(SERVER_PORT , &server.sin_addr);while(1){printf("Enter a line: \n"); fget(line,BUFLEN,stdin);line[strlen(line) -1 ]=0;printf("send a line to server \n");sendto(sock,line,strlen(len),0,(struct sockaddr *)&server,slen);memset(line ,0 ,BUFLEN);printf("try to receive a line from server \n");rlen =recvfrom (sock,line,BUFLEN,0,(struct sockaddr *)&server,slen);printf("rlen =%d : line=%s \n" ,rlen ,line);}}?
六、TCP 回顯服務(wù)器-客戶機
服務(wù)器端
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include<unistd.h> #define MAX 256 #define SERVER_IP "127.0.0.1" #define SERVER_HOST "localhost" #define SERVER_PORT 1234struct sockaddr_in server_addr ,client_addr; int mysock,csock; //sock的文件描述符 int r,n; //輔助變量 socklen_t len; int server_init(){printf("=============server init========\n");printf("1. create a TCP socket\n");mysock = socket (AF_INET,SOCK_STREAM,0);if(mysock < 0){printf("socket call failed\n"); exit(1);}printf("2. fill server_addr with host_ip and port number \n");server_addr .sin_family = AF_INET;server_addr .sin_port = htons(SERVER_PORT);server_addr .sin_addr.s_addr = htonl(INADDR_ANY);printf("3. bind socket to server address \n");r =bind (mysock ,(struct sockaddr *) & server_addr ,sizeof (server_addr ));if( r<0){printf("bind call failed\n"); exit(3);}printf(" hostname =%s, port = %d \n", SERVER_HOST ,SERVER_PORT);listen(mysock , 5 );printf("============init done ===========\n");return 0; }int main (){char line [MAX];server_init();while (1){printf("server accepting new connection... \n");len = sizeof(client_addr);csock = accept(mysock,(struct sockaddr *)&client_addr,&len); if(csock <0){printf("accept failed\n"); exit(1);}printf("Server: accept a client :IP=%s , port = %d \n",inet_ntoa(client_addr.sin_addr) ,ntohs(client_addr.sin_port)); while(1){n=read(csock,line,MAX);if(n=0) {printf("clinet dead ,server loop\n");close(csock); break;}printf("read n =%d byte;line = %s \n", n,line);n=write(csock,line,MAX);printf("write n =%d byte;ECHO = %s \n", n,line);printf("ready for next request\n");}}}?客戶端:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include<unistd.h>#define MAX 256 #define SERVER_HOST "localhost" #define SERVER_PORT 1234struct sockaddr_in server_addr ; int sock,r; int client_init(){printf("=============client init========\n");printf("1. create a TCP socket\n");sock = socket (AF_INET,SOCK_STREAM,0);if(sock < 0){printf("socket call failed\n"); exit(1);}printf("2. fill server_addr with host_ip and port number \n");server_addr .sin_family = AF_INET;server_addr .sin_port = htons(SERVER_PORT);server_addr .sin_addr.s_addr = htonl(INADDR_ANY);printf("3. connecting to server \n");r = connect (sock ,(struct sockaddr *) & server_addr ,sizeof (server_addr )); if( r<0){printf("bind call failed\n"); exit(3);}printf(" hostname =%s, port = %d \n", SERVER_HOST ,SERVER_PORT);printf("============client init done ===========\n");return 0; }int main (){char line [MAX] , ans[MAX];int n; client_init();printf(" ********processing loop *******************");while (1){printf("put a line... \n");bzero(line ,MAX);fgets(line,MAX,stdin);line[strlen(line) - 1] = 0;if(line[0] ==0) exit(0);n=write(sock,line,MAX);printf("client : wrote n =%d bytes ; line %s :\n", n , line);n =read(sock ,ans,MAX); printf("client : read n =%d bytes ; line %s :\n", n , line);}}總結(jié)
以上是生活随笔為你收集整理的Linux C : TCP/IP 和 网络编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux C: IO库函数,文件流缓冲
- 下一篇: 原码、反码、补码、移码的表示