• 《TCP/IP网络编程》阅读笔记--Socket类型及协议设置


    目录

    1--协议的定义

    2--Socket的创建

    2-1--协议族(Protocol Family)

    2-2--Socket类型(Type)

    3--Linux下实现TCP Socket

    3-1--服务器端

    3-2--客户端

    3-3--编译运行

    4--Windows下实现 TCP Socket

    4-1--TCP服务端

    4-2--TCP 客户端

    4-3--编译运行


    1--协议的定义

            协议是对话中使用的通信规则,拓展到计算机领域可整理为“计算机间对话必备通信规则”。简言之,协议就是为了完成数据交换而定好的约定

    2--Socket的创建

    1. #include
    2. int socket(int domain, int type, int protocol);
    3. // 创建成功返回文件描述符,创建失败返回-1;
    4. // domain 表示 socket 中使用的协议族(Protocol Family)信息;
    5. // type 表示 socket 数据传输的类型信息;
    6. // protocol 表示计算机间通信中使用的协议信息(TCP、UDP);

    2-1--协议族(Protocol Family)

    头文件 sys/socket.h 中声明的协议族

            ①:PF_INET 表示 IPv4 互联网协议族;

            ②:PF_INET6 表示 IPv6 互联网协议族;

            ③:PF_LOCAL 表示本地通信的 UNIX 协议族;

            ④:PF_PACKET 表示底层 Socket 的协议族

            ⑤:PF_IPX 表示 IPX Novell 协议族;

            Socket 实际采用的最终协议信息通过 socket 函数的第三个参数(protocol)传递的,在指定的协议族范围内通过第一个参数决定第三个参数;

    2-2--Socket类型(Type)

            Socket 类型指的是 Socket 的数据传输方式,一般决定了协议族并不能同时决定数据传输方式,因为同一个协议族中可能存在多种数据传输方式

            以下说明两种常用的 Socket 类型:

    面向连接的 Socket:SOCK_STREAM,特点如下:

            ① 传输过程中数据不会丢失;

            ② 按序传输数据;

            ③ 传输的数据不存在数据边界;

    面向连接的 Socket 只能与另外一个同样特性的 Socket 进行连接;

    一句话概括面向连接的 Socket :可靠的、按序传递的、基于字节面向连接的数据传输方式;

    面向消息的 Socket:SOCK_DGRAM,特点如下:

            ① 强调快速传输而非传输顺序;

            ② 传输的数据可能丢失也可能销毁;

            ③ 传输的数据有数据边界,即意味着接收数据的次数应和传输次数相同;

            ④ 限制每次传输的数据大小;

    一句话概括面向消息的 Socket :不可靠的、不按序传递的、以数据的高速传输为目的的 Socket;

            参数 PF_INET 指 IPv4 网络协议族,SOCK_STREAM 指面向连接的数据传输,满足以上两个条件的协议只有 IPPPOTO_TCP,即可通过以下方式创建 TCP Socket:

    int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

            同理,SOCK_DGRAM 指面向消息的数据传输方式,满足条件的协议只有 IPPPOTO_UDP,即可通过以下方式创建 UDP Socket:

    int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

    3--Linux下实现TCP Socket

    3-1--服务器端

    1. // gcc tcp_server.c -o tcp_server
    2. // ./tcp_server 9190
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. void error_handling(char *message){
    10. fputs(message, stderr);
    11. fputc('\n', stderr);
    12. exit(1);
    13. }
    14. int main(int argc, char *argv[]){
    15. int serv_sock;
    16. int clnt_sock;
    17. struct sockaddr_in serv_addr;
    18. struct sockaddr_in clnt_addr;
    19. socklen_t clnt_addr_size;
    20. char message[] = "Hello World!";
    21. if(argc != 2){
    22. printf("Usage : %s \n", argv[0]);
    23. exit(1);
    24. }
    25. serv_sock = socket(PF_INET, SOCK_STREAM, 0); // 调用 socket 函数创建socket
    26. if(serv_sock == -1){
    27. error_handling("socket() error");
    28. }
    29. memset(&serv_addr, 0, sizeof(serv_addr));
    30. serv_addr.sin_family = AF_INET;
    31. serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    32. serv_addr.sin_port = htons(atoi(argv[1]));
    33. // 调用 bind 函数分配 ip 地址和端口号
    34. if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1){
    35. error_handling("bind() error");
    36. }
    37. // 调用 listen 函数将 socket 转为可接收连接状态
    38. if(listen(serv_sock, 5) == -1){
    39. error_handling("listen() error");
    40. }
    41. clnt_addr_size = sizeof(clnt_addr);
    42. // 调用 accept 函数受理连接请求
    43. // 没有连接请求的情况下,不会有返回情况,直到有连接请求为止
    44. clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size);
    45. if(clnt_sock == -1){
    46. error_handling("accept() error");
    47. }
    48. // 调用 write 函数传输数据
    49. write(clnt_sock, message, sizeof(message));
    50. close(clnt_sock);
    51. close(serv_sock);
    52. return 0;
    53. }

    3-2--客户端

    1. // gcc tcp_client.c -o tcp_client
    2. // ./tcp_client 127.0.0.1 9190
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. void error_handling(char *message){
    10. fputs(message, stderr);
    11. fputc('\n', stderr);
    12. exit(1);
    13. }
    14. int main(int argc, char *argv[]){
    15. int sock;
    16. struct sockaddr_in serv_addr;
    17. char message[30];
    18. int str_len;
    19. int idx = 0, read_len = 0;
    20. if(argc != 3){
    21. printf("Usage : %s \n", argv[0]);
    22. exit(1);
    23. }
    24. sock = socket(PF_INET, SOCK_STREAM, 0);
    25. if(sock == -1){
    26. error_handling("socket() error");
    27. }
    28. memset(&serv_addr, 0, sizeof(serv_addr));
    29. serv_addr.sin_family = AF_INET;
    30. serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    31. serv_addr.sin_port = htons(atoi(argv[2]));
    32. if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1){
    33. error_handling("connect() error!");
    34. }
    35. while(read_len = read(sock, &message[idx++], 1)){
    36. if(read_len == -1){
    37. error_handling("read() error!");
    38. }
    39. str_len += read_len;
    40. }
    41. printf("Message from server : %s \n", message);
    42. printf("Function read call count: %d \n", str_len);
    43. close(sock);
    44. return 0;
    45. }

    3-3--编译运行

    1. # TCP服务端
    2. gcc tcp_server.c -o tcp_server
    3. ./tcp_server 9190
    4. # TCP客户端
    5. gcc tcp_client.c -o tcp_client
    6. ./tcp_client 127.0.0.1 9190

    4--Windows下实现 TCP Socket

    4-1--TCP服务端

    1. // gcc tcp_server_win.c -o tcp_server_win -lwsock32
    2. // tcp_server_win 9190
    3. #include
    4. #include
    5. #include
    6. // 打印错误信息
    7. void ErrorHandling(char* message){
    8. fputs(message, stderr);
    9. fputc('\n', stderr);
    10. exit(1);
    11. }
    12. int main(int argc, char* argv[]){
    13. WSADATA wsaData;
    14. SOCKET hServSock, hClntSock;
    15. SOCKADDR_IN servAddr, clntAddr;
    16. int szClntAddr;
    17. char message[] = "Hello World!";
    18. if(argc != 2){
    19. printf("Usage: %s \n", argv[0]);
    20. exit(1);
    21. }
    22. if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ // 初始化套接字库
    23. ErrorHandling("WSAStartup() error!");
    24. }
    25. hServSock = socket(PF_INET, SOCK_STREAM, 0); // 创捷socket
    26. if(hServSock == INVALID_SOCKET){
    27. ErrorHandling("socket() error!");
    28. }
    29. memset(&servAddr, 0, sizeof(servAddr));
    30. servAddr.sin_family = AF_INET;
    31. servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    32. servAddr.sin_port = htons(atoi(argv[1])); // 端口
    33. if(bind(hServSock, (SOCKADDR*) &servAddr, sizeof(servAddr)) == SOCKET_ERROR){ // 给 socket 分配 ip 地址和端口号
    34. ErrorHandling("bind() error!");
    35. }
    36. if(listen(hServSock, 5) == SOCKET_ERROR){ // 置于listen状态,使socket可接收客户端连接请求
    37. ErrorHandling("listen() error!");
    38. }
    39. szClntAddr = sizeof(clntAddr);
    40. hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr); // 使socket受理客户端的连接请求
    41. if(hClntSock == INVALID_SOCKET){
    42. ErrorHandling("accept() error!");
    43. }
    44. send(hClntSock, message, sizeof(message), 0); // 向连接的客户端发送数据
    45. closesocket(hClntSock);
    46. closesocket(hServSock);
    47. WSACleanup(); // 注销初始化的套接字库
    48. return 0;
    49. }

    4-2--TCP 客户端

    1. // gcc tcp_client_win.c -o tcp_client_win -lwsock32
    2. // tcp_client_win 127.0.0.1 9190
    3. #include
    4. #include
    5. #include
    6. // 打印错误信息
    7. void ErrorHandling(char* message){
    8. fputs(message, stderr);
    9. fputc('\n', stderr);
    10. exit(1);
    11. }
    12. int main(int argc, char* argv[]){
    13. WSADATA wsaData;
    14. SOCKET hSocket;
    15. SOCKADDR_IN servAddr;
    16. char message[30];
    17. int strLen = 0;
    18. int idx = 0, readLen = 0;
    19. if(argc != 3){
    20. printf("Usage: %s \n", argv[0]);
    21. exit(1);
    22. }
    23. if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ // 初始化套接字库
    24. ErrorHandling("WSAStartup() error!");
    25. }
    26. hSocket = socket(PF_INET, SOCK_STREAM, 0); // 创捷面向连接的 TCP Socket
    27. if(hSocket == INVALID_SOCKET){
    28. ErrorHandling("socket() error!");
    29. }
    30. memset(&servAddr, 0, sizeof(servAddr));
    31. servAddr.sin_family = AF_INET;
    32. servAddr.sin_addr.s_addr = inet_addr(argv[1]);
    33. servAddr.sin_port = htons(atoi(argv[2]));
    34. if(connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR){ // 向服务器端发送连接请求
    35. ErrorHandling("connect() error!");
    36. }
    37. while(readLen = recv(hSocket, &message[idx++], 1, 0)){ // 接收服务器发来的数据
    38. if(readLen == -1) ErrorHandling("read() error!");
    39. strLen += readLen;
    40. if(message[idx - 1] == '\0') break; // 读取到最后一个字节
    41. }
    42. printf("Message from server: %s \n", message);
    43. printf("Function read call count: %d \n", strLen);
    44. closesocket(hSocket);
    45. WSACleanup(); // 注销初始化的Winsock库
    46. return 0;
    47. }

    4-3--编译运行

    1. # TCP服务端
    2. gcc tcp_server_win.c -o tcp_server_win -lwsock32
    3. tcp_server_win 9190
    4. # TCP客户端
    5. gcc tcp_client_win.c -o tcp_client_win -lwsock32
    6. tcp_client_win 127.0.0.1 9190

  • 相关阅读:
    Pom文件的依赖与starter启动器的作用
    2022全球数字经济大会开元之境 金谷诺亚-李刚:数字藏品业态
    Wireshark Lua插件入门
    Mistral AI 推出最新Mistral Large模型,性能仅次于GPT 4
    Unity之3D物理导航系统
    FactoryBean解读
    DM-VERITY流程分析
    常见的Web安全漏洞有哪些,Web安全漏洞常用测试方法介绍
    jenkins 部署spring-boot 项目
    【0117】pg_multixact管理器
  • 原文地址:https://blog.csdn.net/weixin_43863869/article/details/132654240