第一章 第二章 第三章 网络字节序与地址转换
保存数据方式
解析数据方式
大端序
高位字节放在低位地址
小端序
低位字节放在高位地址
字节序转换相关函数 short–>占用2字节、long–>占用4字节(Linux)
函数名
作用等
htonl()
用于IP地址转换
htons()
用于端口号转换
字节序转换函数实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> #include <arpa/inet.h> int main (int argc, char **argv) { unsigned short host_port = 0x1234 ; unsigned short net_port; unsigned long host_addr = 0x12345678 ; unsigned long net_addr; net_addr = htonl(host_addr); net_port = htons(host_port); printf ("Host order port: %#x\n" , host_port); printf ("Net order port: %#x\n" , net_port); printf ("Host order address: %#lx\n" , host_addr); printf ("Net order address: %#lx\n" , net_addr); return 0 ; } Host order port: 0x1234 Net order port: 0x3412 Host order address: 0x12345678 Net order address: 0x78563412
数据在传输过程中不需要考虑字节序问题(除了向sockaddr_in填充数据外)
网络地址的初始化与分配 将字符串信息转换为网络字节序的整数型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <arpa/inet.h> in_addr_t inet_addr (const char *string ) ;成功返回32 位大端序整数型值,失败返回INADDR_NONE #include <stdio.h> #include <arpa/inet.h> int main (int argc, char **argv) { char *addr1 = "1.2.3.4" ; char *addr2 = "1.2.3.256" ; unsigned long conv_addr = inet_addr(addr1); if (conv_addr == INADDR_NONE) printf ("Error occurred! \n" ); else printf ("Network ordered integer addr: %#lx \n" , conv_addr); conv_addr = inet_addr(addr2); if (conv_addr == INADDR_NONE) printf ("Error occurred! \n" ); else printf ("Network ordered integer addr: %#lx \n" , conv_addr); return 0 ; } Network ordered integer addr: 0x4030201 Error occurred! 一个字节能表示的最大整数位255 ,所以第二个错的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <arpa/inet.h> int inet_aton (const char * string , struct in_addr *addr) ;成功返回1 ,失败返回0 string : 含有需要转换的IP地址信息的字符串地址值addr: 将保存转换结果的in_addr结构体变量的地址值 #include <stdio.h> #include <arpa/inet.h> #include <stdlib.h> void error_handler (char *message) ;int main (int argc, char **argv) { char *addr = "127.232.124.79" ; struct sockaddr_in addr_inet ; if (!inet_aton(addr, &addr_inet.sin_addr)) { error_handler("Conversion error" ); } else { printf ("NetWork order integer addr: %#x \n" , addr_inet.sin_addr.s_addr); } return 0 ; } void error_handler (char *message) { fputs (message, stderr ); fputc('\n' , stderr ); exit (1 ); } NetWork order integer addr: 0x4f7ce87f
inet_addr函数和inet_aton函数功能完全相同。但是inet_aton函数会自动把结果存入sockaddr_in结构体中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <arpa/inet.h> char *inet_aton (struct in_addr addr) ;成功返回转换字符串地址值,失败返回-1 #include <stdio.h> #include <arpa/inet.h> #include <stdlib.h> #include <string.h> int main (int argc, char **argv) { struct sockaddr_in addr1 , addr2 ; char *str_ptr; char str_arr[20 ]; addr1.sin_addr.s_addr = htonl(0x1020304 ); addr2.sin_addr.s_addr = htonl(0x1010101 ); str_ptr = inet_ntoa(addr1.sin_addr); strcpy (str_arr, str_ptr); printf ("notation1 :%s \n" , str_ptr); inet_ntoa(addr2.sin_addr); printf ("notation2 :%s \n" , str_ptr); printf ("notation3 :%s \n" , str_arr); return 0 ; } notation1 :1.2 .3 .4 notation2 :1.1 .1 .1 notation3 :1.2 .3 .4
第四章 理解TCP和UDP 根据传输方式的不同,基于网络协议的套接字一般分为TCP套接字和UDO套接字。因为TCP套接字是面向连接,因此又称为基于流(stream)的套接字。
TCP/IP协议栈
TCP/IP协议栈分4层:链路层、IP层、传输层、应用层
OSI模型分7层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
基于TCP的服务端/客户端 TCP服务端默认函数调用顺序:
socket() 创建套接字
bind() 分配套接字地址
listen() 等待连接请求状态
accept() 允许连接
read()/write() 数据交换
close() 断开连接
TCP客户端默认函数调用顺序
socket()
connect()
read()/write()
close()
函数调用关系 服务器创建套接字后连续调用bind、listen函数进入等待状态,客户端通过调用connect函数发起连接请求。
注意:客户端只有等到服务端调用listen函数以后才能调用connect函数。同时,客户端调用connect函数前,服务端可能率先调用accept函数,当然,磁石服务端在调用accept函数时进入阻塞(blocking)状态,知道客户端调用connect函数为止。
实现迭代服务器端/客户端 实现服务端将客户端传输的字符串数据原封不动的传回客户端。
目前该服务端同一时刻只能服务一个客户端。
迭代回声服务器端/客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUF_SIZE 1024 void error_handler (char *message) ;int main (int argc, char **argv) { int server_sock, client_sock; char message[BUF_SIZE]; int str_len, i; struct sockaddr_in server_addr , client_addr ; socklen_t client_addr_size; if (argc != 2 ) { printf ("Usage: %s <port>\n" , argv[0 ]); exit (1 ); } server_sock = socket(PF_INET, SOCK_STREAM, 0 ); if (server_sock == -1 ) { error_handler("socket() error" ); } memset (&server_addr, 0 , sizeof (server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(atoi(argv[1 ])); if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof (server_addr)) == -1 ) { error_handler("bind() error" ); } if (listen(server_sock, 5 ) == -1 ) { error_handler("listen() error" ); } client_addr_size = sizeof (client_addr_size); for (int i = 0 ; i < 5 ; i++) { client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_size); if (client_sock == -1 ) { error_handler("accept() error" ); } else { printf ("Conected client %d\n" , i + 1 ); } while ((str_len = read(client_sock, message, BUF_SIZE)) != 0 ) write(client_sock, message, str_len); close(client_sock); } close(server_sock); return 0 ; } void error_handler (char *message) { fputs (message, stderr ); fputc('\n' , stderr ); exit (1 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUF_SIZE 1024 void error_handler (char *message) ;int main (int argc, char **argv) { int sock; char message[BUF_SIZE]; int str_len = 0 ; struct sockaddr_in server_addr ; if (argc != 3 ) { printf ("Usage: %s <IP> <PORT>\n" , argv[0 ]); exit (1 ); } sock = socket(AF_INET, SOCK_STREAM, 0 ); if (sock == -1 ) { error_handler("socket() error" ); } memset (&server_addr, 0 , sizeof (server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(argv[1 ]); server_addr.sin_port = htons(atoi(argv[2 ])); if (connect(sock, (struct sockaddr *)&server_addr, sizeof (server_addr)) == -1 ) { error_handler("connect() error" ); } else { puts ("Connect..............\n" ); } while (1 ) { fputs ("Input message(Q to quit):" , stdout ); fgets(message, BUF_SIZE, stdin ); if (!strcmp (message, "q\n" ) || !strcmp (message, "Q\n" )) break ; write(sock, message, strlen (message)); str_len = read(sock, message, BUF_SIZE - 1 ); message[str_len] = 0 ; printf ("Message from server: %s\n" , message); } close(sock); return 0 ; } void error_handler (char *message) { fputs (message, stderr ); fputc('\n' , stderr ); exit (1 ); }
第五章 第六章 第七章 第八章