Linux系统编程笔记1

内容来自《unix环境高级编程》和《tcp/ip网络编程》,做些笔记整理一下,方便之后阅读。

tcp连接:可靠(一般不发生数据丢失),有序(先发先到),不存在边界 ----传送带模型

套接字约等于文件,fd文件描述符代表着文件编号,也是套接字的编号。每次系统分配的最小的未用的描述符

 套接字内部有缓冲(字节数组),有可能在好几次向套接字write后,等缓冲区填满后直接调用一次read,也可能分多次调用read,如果发生从缓冲区read的速度跟不上导致缓冲区填满,此时不会发生数据丢失(tcp连接),这种情况下write将阻塞。

udp连接:快速(相对来说容易丢包),无序,有边界,限制每次传输大小(寄信模型)

三种类型的标准I/O缓冲

(1)全缓冲,填满缓冲区后才执行I/O操作,可以主动flush冲洗缓冲区

(2)行缓冲,遇到换行符执行I/O操作

(3)不带缓冲,不对字符进行缓冲存储,例如标准错误流stderr

TCP:

  服务端:socket创建套接字->bind绑定套接字与ip地址和端口号->listen宣告可接收请求了->accept受理请求

  客户端:socket创建套接字->connect连接服务端地址

bind绑定服务器中具体的IP地址,建造了服务器要和外界通讯的大门,listen把大门打开,连接请求可以来排队了,accept受理请求后分配一个专门用来和该客户端通信的fd,这个fd和客户端调用socket函数分配的fd组成一个pair对,准确来说是套接字组成pair,就像书中开头讲到的插头与插座的概念,由此形成一条通路,进行网络通信。这两个fd的配对我理解是通过ip地址+端口唯一的识别出了他们的彼此。因为accept的时候有传出参数来表示请求的地址结构。

         

 IPV4  D类ip地址,前三字节表示网络id,第四字节表示主机id,先找网络地址,再找主机地址

大端序:高位字节存放低位地址

小端绪:高位字节存放高位地址

 tcp/ip网络字节序指定大端序

htonl、htons、ntohl、ntohs(主机字节序与网络字节序的转换)

inet_addr(inet_aton)、inet_ntoa(二进制地址格式(网络字节序)与点分十进制字符表示的转换)

INADDR_ANY自动获取运行服务器端的计算机IP地址。

网络模型:物理层(光纤,电缆),数据链路层(网卡),网络层(IP、路由),传输层(TCP/UDP),应用层(HTTP等)

IP是面向消息的不可靠的协议。传输顺序与传输本身是不可靠的。

客户端只有在服务端listen后才能调用connect

tcp滑动窗口协议,write函数在数据移到输出缓冲时返回,如果此时关闭套接字也会继续传输输出缓冲中的数据,关闭套接字会丢失输入缓冲的数据

tcp经典的三次握手,四次挥手,syn,ack,fin等各个状态需要掌握,超时重传time-out,以及最后关闭连接前的time-wait

 tcp在不可靠的IP层进行流控制(收发数据过程中为保证可靠性而添加的流控制),udp缺少这种流控制机制。udp的传输速度快,但在每次交换的数据量越大,tcp传输速度越接近udp的传输速度,因为tcp的时间主要用在建立连接,三次握手四次挥手和收发过程中的流控制(SEQ,ACK)当每次交换的数据量越大,连接的时间占比就越小,所以就越接近udp的传输速度。

传输压缩文件时必须使用tcp,传输多媒体数据,如音频视频时丢失一部分问题不大,更注重传输速度,所以选用udp,

 tcp中的套接字时一一对应,先建立好连接

udp只有创建套接字和交换数据,客户端和服务端都只需要1个套接字,只要都有邮筒,就可以寄向各地,与之通信。(没有listen和accept)

每个套接字都会有一个ip地址和端口号,tcp连接时bind,accept,connect时都会分配,udp中通过bind,sendto,recvfrom都会自动分配

udp是就有边界的协议,调用几次输出就要调用几次输入来接收,不同于tcp可以一次读入

 未连接的udp套接字(默认,所以每次sendto和recvfrom都要注册一下ip地址和端口在struct sockaddr_in)和有连接的udp套接字(先调用connect绑定目标ip和端口,然后直接read和write,在每次都给同一地址发消息时这样能省去每次都recvfrom和sendto时注册地址和删除地址信息的时间)

 Nagle算法,最大限度进行缓冲,收到ACK后将缓冲的数据打包再发出去,尽量使用nagle算法,不使用nagle算法容易对网络流量造成负面影响。网络流量不受太大影响时可不使用nagle算法,传输快,无需等待ACK。

 1 //tcp_server.cpp
 2 
 3 #include<iostream>
 4 #include<stdlib.h>
 5 #include<string.h>
 6 #include<unistd.h>
 7 #include<arpa/inet.h>
 8 #include<sys/socket.h>
 9 using namespace std;
10 
11 int main(int argc,char* argv[])
12 {
13     int serv_sock,clnt_sock;
14 
15     struct sockaddr_in serv_addr,clnt_addr;
16     socklen_t clnt_addr_size;
17     char message[] = "hello,world!";
18 
19     if(argc!=2){
20         cout<<"usage "<< argv[0] <<" port"<<endl;
21     }
22 
23     serv_sock = socket(AF_INET,SOCK_STREAM,0);
24     memset(&serv_addr,0,sizeof(serv_addr));
25     serv_addr.sin_family = AF_INET;
26     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
27     serv_addr.sin_port = htons(atoi(argv[1]));
28     bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
29     listen(serv_sock,5);
30     clnt_addr_size = sizeof(clnt_addr);
31     clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_addr_size);
32 
33     write(clnt_sock,message,sizeof(message));
34     close(clnt_sock);
35     close(serv_sock);
36     return 0;
37 }
 1 //tcp_client.cpp
 2 
 3 #include<iostream>
 4 #include<stdlib.h>
 5 #include<string.h>
 6 #include<unistd.h>
 7 #include<arpa/inet.h>
 8 #include<sys/socket.h>
 9 using namespace std;
10 
11 int main(int argc,char* argv[])
12 {
13     int clnt_sock;
14 
15     struct sockaddr_in serv_addr;
16     //socklen_t clnt_addr_size;
17     char message[30];
18 
19     if(argc!=3){
20         cout<<"usage "<< argv[0]<<" <address> <port>"<<endl;
21     }
22 
23     clnt_sock = socket(AF_INET,SOCK_STREAM,0);
24     memset(&serv_addr,0,sizeof(serv_addr));
25     serv_addr.sin_family = AF_INET;
26     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
27     serv_addr.sin_port = htons(atoi(argv[2]));
28     //bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
29     //listen(serv_sock,5);
30     //clnt_addr_size = sizeof(clnt_addr);
31     connect(clnt_sock,(struct sockaddr*) &serv_addr,sizeof(serv_addr));
32     int idx = 0; int read_len = 0; int count = 0;
33     while(read_len = read(clnt_sock,&message[idx],1)) //每次读一个字节
34     {
35         if(read_len == -1)
36         {
37             cout<<"read error!"<<endl;
38         }
39         idx++;count++;
40     }
41     cout<<"message from server: "<<message<<endl;
42     cout<<"read function call count: "<<count<<endl;
43     close(clnt_sock);
44     return 0;
45 }
 1 //echo_server.cpp
 2 
 3 #include<iostream>
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6 #include<string.h>
 7 #include<unistd.h>
 8 #include<arpa/inet.h>
 9 #include<sys/socket.h>
10 using namespace std;
11 
12 #define BUF_SIZE 1024
13 
14 int main(int argc, char* argv[])
15 {
16     int serv_sock, clnt_sock;
17 
18     struct sockaddr_in serv_addr, clnt_addr;
19     socklen_t clnt_addr_size;
20     char message[BUF_SIZE];
21 
22     if (argc != 2) {
23         cout << "usage " << argv[0] << " port" << endl;
24     }
25 
26     serv_sock = socket(AF_INET, SOCK_STREAM, 0);
27     memset(&serv_addr, 0, sizeof(serv_addr));
28     serv_addr.sin_family = AF_INET;
29     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
30     serv_addr.sin_port = htons(atoi(argv[1]));
31     bind(serv_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr));
32     listen(serv_sock, 5);
33     clnt_addr_size = sizeof(clnt_addr);
34 
35     int str_len = 0;
36     for (int i = 0; i < 5; ++i)
37     {
38         clnt_sock = accept(serv_sock, (struct sockaddr*) & clnt_addr, &clnt_addr_size);
39         printf("connect client %d \n", i + 1);
40         while ((str_len = read(clnt_sock, message, BUF_SIZE)) != 0)
41             write(clnt_sock, message, str_len);
42         close(clnt_sock);
43     }
44     close(serv_sock);
45     return 0;
46 }
 1 //echo_client.cpp
 2 
 3 #include<iostream>
 4 #include<stdio.h>
 5 #include<stdlib.h>
 6 #include<string.h>
 7 #include<unistd.h>
 8 #include<arpa/inet.h>
 9 #include<sys/socket.h>
10 using namespace std;
11 
12 #define BUF_SIZE 1024
13 
14 int main(int argc, char* argv[])
15 {
16     int clnt_sock;
17     struct sockaddr_in serv_addr;
18     char message[BUF_SIZE];
19 
20     if (argc != 3) {
21         cout << "usage " << argv[0] << " <address> <port>" << endl;
22     }
23 
24     clnt_sock = socket(AF_INET, SOCK_STREAM, 0);
25     memset(&serv_addr, 0, sizeof(serv_addr));
26     serv_addr.sin_family = AF_INET;
27     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
28     serv_addr.sin_port = htons(atoi(argv[2]));
29 
30     connect(clnt_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr));
31     puts("connected...");
32 
33     int str_len,recv_len,recv_cnt;
34     while (1)
35     {
36         fputs("input q to quit: ", stdout);
37         fgets(message, BUF_SIZE, stdin);   //fgets会读入'\n'
38         if (message == "q\n" || message == "Q\n")
39             break;
40 
41         str_len = write(clnt_sock, message, strlen(message));
42         recv_len = 0;
43         while (recv_len < str_len)
44         {
45             recv_cnt = read(clnt_sock, &message[recv_len], BUF_SIZE - 1);
46             recv_len += recv_cnt;
47         }
48         message[BUF_SIZE] = '\0';
49         printf("message from server: %s", message);
50     }
51     close(clnt_sock);
52     return 0;
53 }
 1 //echo_server_udp.cpp
 2 
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include <string.h>
 6 #include <unistd.h>
 7 #include <arpa/inet.h>
 8 #include <sys/socket.h>
 9 
10 #define BUF_SIZE     30
11 
12 int main(int argc,char* argv[])
13 {
14     int sock;
15     struct sockaddr_in serv_addr,clnt_addr;
16     socklen_t clnt_size; //socklen_t 地址长度类型
17     char message[BUF_SIZE];
18     //printf("hello");
19     if (argc != 2)
20     {
21         printf("usage %s <port>\n", argv[0]);
22         exit(1);
23     }
24 
25     printf("server start...\n");//printf向终端设备打印,是行缓冲的,加上'\n',才能立即看到显示
26     sock = socket(PF_INET, SOCK_DGRAM, 0);
27     if (sock == -1)
28     {
29         printf("socket error");
30         exit(1);
31     }
32     memset(&serv_addr, 0, sizeof(serv_addr));
33     serv_addr.sin_family = AF_INET;
34     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
35     serv_addr.sin_port = htons(atoi(argv[1]));
36     bind(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
37     int str_len;
38     
39     printf("socket created..\n");
40     while (1)
41     {
42         clnt_size = sizeof(clnt_addr);
43         printf("start...\n");
44         str_len = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr*)&clnt_addr, &clnt_size);
45         printf("recv over\n");
46         sendto(sock, message, str_len, 0, (struct sockaddr*)&clnt_addr, clnt_size);
47         printf("send over\n");
48     }
49     close(sock);
50     return 0;
51 }
 1 //echo_client_udp.cpp
 2 
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #include <string.h>
 6 #include <unistd.h>
 7 #include <arpa/inet.h>
 8 #include <sys/socket.h>
 9 
10 #define BUF_SIZE 30
11 
12 int main(int argc,char* argv[])
13 {
14     int sock;
15     struct sockaddr_in serv_addr,from_addr;
16     char message[BUF_SIZE];
17     if (argc != 3)
18     {
19         printf("usage %s <ip> <port>\n", argv[0]);
20     }
21     sock = socket(AF_INET, SOCK_DGRAM, 0);
22     memset(&serv_addr, 0, sizeof(serv_addr));
23     serv_addr.sin_family = AF_INET;
24     //inet_addr(inet_aton)将点分十进制转换为二进制的网络字节序,此时不需要htonl,套了一层htonl后一直不能收发消息
25     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
26     serv_addr.sin_port = htons(atoi(argv[2]));
27 
28     socklen_t addr_size = sizeof(from_addr);
29     int str_len;
30     while (1)
31     {
32         fputs("input message and press q to quit:\n", stdout);
33         //printf("%d\n",sizeof(message));
34         fgets(message,sizeof(message), stdin);
35         //printf("%c\n", message[0]);
36         if (!strcmp(message, "q\n"))
37             break;
38         sendto(sock, message, strlen(message), 0, (struct sockaddr*) &serv_addr, sizeof(serv_addr));
39         printf("send over!\n");
40         str_len = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr*) &from_addr, &addr_size);
41         printf("recv over!\n");
42         message[str_len] = '\0';
43         printf("Message from other: %s", message);
44     }
45     close(sock);
46     return 0;
47 }

 

posted @ 2019-05-23 21:15  小蜗牛慢跑  阅读(282)  评论(0编辑  收藏  举报