zoukankan      html  css  js  c++  java
  • socket编程

    一、sockket定义

    在计算机通信领域,socket翻译为:“套接字”。他是计算机之间通讯的一种的方式。IP地址和端口能够在广袤的互联网中定位到要通信的程序,协议和数据传输方式规定了如何传输数据,有了这些,两台计算机就可以通信了。

    二、实现通信的条件

    两台计算机之间要通信必须知道对方的IP地址和端口号

    2.1IP地址(IP Address)

      计算机分布在全世界,彼此要通信,必须知道对方的确切的位置,通常是通过确定IP地址来进行通信的,我们计算机不知道IP地址对应的地理位置,通常是将IP地址封装到发送的数据包中,交给路由器处理,路由器通过算法,找到目标计算机,并将数据包传给他,完成一次通信。

    目前主要有IPV4和IPV6两种,因IPV4资源已经耗尽,现阶段在推广IPV6

    2.2端口(Port)

      有了IP地址,虽然可以找到目标机,但是任然不能进行通信,因为通常一台计算机同时提供多种网路服务,通常有:FTP、SMTP、Web等服务,仅有IP地址,计算机可以接受到数据,但是不知道将数据包交给哪个网络进行处理,因此还不能正常通信。

      计算机为了区分各种网络程序,会为每一个程序分配独一无二的端口号,例如:网络服务:80端口,FTP:21   SMTP:25。端口是虚拟的,可以将端口理解为门户,数据需要通过门户流进流出,每一个门户都有一个门牌号,就是端口号。

    三、通信协议及数据传输方式

      3.1 通信协议

    协议(Protocol)就是网络通信的约定,通信的双方必须都遵守才能正常收发数据。协议有很多种,例如 TCP、UDP、IP 等,通信的双方必须使用同一协议才能通信。协议是一种规范,由计算机组织制定,规定了很多细节,例如,如何建立连接,如何相互识别等。

      所谓协议族(Protocol Family),就是一组协议(多个协议)的统称。最常用的是 TCP/IP 协议族,它包含了 TCP、IP、UDP、Telnet、FTP、SMTP 等上百个互为关联的协议,由于 TCP、IP 是两种常用的底层协议,所以把它们统称为 TCP/IP 协议族。

      2.2数据传输方式

      计算机之间有很多数据传输方式,各有优缺点,常用的有两种:SOCK_STREAM 和 SOCK_DGRAM。
      1) SOCK_STREAM 表示面向连接的数据传输方式。数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢。常见的 http 协议就使用 SOCK_STREAM 传输数据,因为要确保数据的正确性,否则网页不能正常解析。
      2) SOCK_DGRAM 表示无连接的数据传输方式。计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。因为 SOCK_DGRAM 所做的校验工作少,所以效率比 SOCK_STREAM 高。

      QQ 视频聊天和语音聊天就使用 SOCK_DGRAM 传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响。

     四、window/Linux编程实例

    4.1 windows下Socket编程实例:

    4.1.1 server.cpp

     1 #include<stdio.h>
     2 #include<winsock2.h>
     3 #pragma comment(lib,"ws2_32.lib")
     4 
     5 int main()
     6 {
     7     // 初始化
     8     WSAData wsaData;
     9     WSAStartup(MAKEWORD(2,2),&wsaData);
    10     //创建套接字
    11     SOCKET serverSock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    12     //绑定套接字
    13     sockaddr_in sockAddr;
    14     memset(&sockAddr, 0, sizeof(sockAddr));//每个字节都填充0
    15     sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//具体的IP地址
    16     sockAddr.sin_family = PF_INET;//使用IPV4
    17     sockAddr.sin_port = htons(1234);
    18     bind(serverSock,(SOCKADDR*)&sockAddr,sizeof(SOCKADDR));
    19 
    20     //监听
    21     listen(serverSock,5);
    22     //接受客户端请求
    23     SOCKADDR clntAddr;
    24     int nSize = sizeof(SOCKADDR);
    25     SOCKET clntSock = accept(serverSock,(SOCKADDR*)&clntAddr,&nSize);
    26 
    27     //向客户端发送数据
    28     char *str = "hello world!";
    29     send(clntSock,str,strlen(str)+sizeof(char),NULL);
    30     //关闭套接字
    31     closesocket(clntSock);
    32     closesocket(serverSock);
    33     //终止DLL的使用
    34     WSACleanup();
    35     return 0;
    36 
    37 }
    View Code

    4.2.2 client.cpp

     1 #include<stdio.h>
     2 #include<winsock2.h>
     3 #pragma comment(lib,"ws2_32.lib")
     4 
     5 int main()
     6 {
     7     //初始化
     8     WSADATA wsaData;
     9     WSAStartup(MAKEWORD(2,2),&wsaData);
    10     //创建套接字
    11     SOCKET sock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    12     //向服务器发送请求
    13     sockaddr_in sockAddr;
    14     sockAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    15     sockAddr.sin_family = PF_INET;
    16     sockAddr.sin_port = htons(1234);
    17     connect(sock,(SOCKADDR*)&sockAddr,sizeof(SOCKADDR));
    18     //接受服务器传输的数据
    19     char szBuff[MAXBYTE];
    20     recv(sock,szBuff,MAXBYTE,NULL);
    21     printf("Message from server:%s
    ",szBuff);
    22     //关闭套接字
    23     closesocket(sock);
    24     WSACleanup();
    25     system("pause");
    26     return 0;
    27 }
    View Code

    分别编译server.cpp和client.cpp,选运行server.exe,在运行client.exe,其结果为:Message form server: hello world!

     4.2 Linux下socket编程

      4.2.1 server.cpp

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 #include <arpa/inet.h>
     6 #include <sys/socket.h>
     7 #include <netinet/in.h>
     8 
     9 int main(){
    10     //创建套接字
    11     int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    12 
    13     //将套接字和IP、端口绑定
    14     struct sockaddr_in serv_addr;
    15     memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    16     serv_addr.sin_family = AF_INET;  //使用IPv4地址
    17     serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
    18     serv_addr.sin_port = htons(1234);  //端口
    19     bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    20 
    21     //进入监听状态,等待用户发起请求
    22     listen(serv_sock, 20);
    23 
    24     //接收客户端请求
    25     struct sockaddr_in clnt_addr;
    26     socklen_t clnt_addr_size = sizeof(clnt_addr);
    27     int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
    28 
    29     //向客户端发送数据
    30     char str[] = "Hello World!";
    31     write(clnt_sock, str, sizeof(str));
    32    
    33     //关闭套接字
    34     close(clnt_sock);
    35     close(serv_sock);
    36 
    37     return 0;
    38 }
    View Code

      4.2.2  client.cpp

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 #include <arpa/inet.h>
     6 #include <sys/socket.h>
     7 
     8 int main() {
     9     //创建套接字
    10     int sock = socket(AF_INET, SOCK_STREAM, 0);
    11 
    12     //向服务器(特定的IP和端口)发起请求
    13     struct sockaddr_in serv_addr;
    14     memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    15     serv_addr.sin_family = AF_INET;  //使用IPv4地址
    16     serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
    17     serv_addr.sin_port = htons(1234);  //端口
    18     connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    19 
    20     //读取服务器传回的数据
    21     char buffer[40];
    22     read(sock, buffer, sizeof(buffer) - 1);
    23 
    24     printf("Message form server: %s
    ", buffer);
    25 
    26     //关闭套接字
    27     close(sock);
    28 
    29     return 0;
    30 }
    View Code

      先编译运行server.cpp

    [admin@lcj ~]$ g++ server.cpp - o server
    [admin@lcj ~]$ . / server
    View Code

      在编译client.cpp

    [admin@lcj ~]$ g++ client.cpp -o client
    [admin@lcj ~]$ ./client
    Message form server: Hello World!
    View Code

      4.3 windows/linux中socket编程差异

      1) Windows 下的 socket 程序依赖 Winsock.dll 或 ws2_32.dll,必须提前加载。DLL 有两种加载方式,请查看:动态链接库DLL的加载

      2) Linux 使用“文件描述符”的概念,而 Windows 使用“文件句柄”的概念;Linux 不区分 socket 文件和普通文件,而 Windows 区分;Linux 下 socket() 函数的返回值为 int 类型,而 Windows 下为 SOCKET 类型,也就是句柄。

      3) Linux 下使用 read() / write() 函数读写,而 Windows 下使用 recv() / send() 函数发送和接收。

      4) 关闭 socket 时,Linux 使用 close() 函数,而 Windows 使用 closesocket() 函数。

      

  • 相关阅读:
    TeamCity+Docker
    k8s 安装步骤
    Gitlab使用时的一些注意事项
    Docker常用命令
    AspNetCore OpenId
    AspNetCore中的IdentityServer4客户端认证模式实现
    AspNet Core 认证
    基于TeamCity的asp.net mvc/core,Vue 持续集成与自动部署
    Cobbler自动化装机脚本
    kubernetes管理机密信息
  • 原文地址:https://www.cnblogs.com/506941763lcj/p/11337192.html
Copyright © 2011-2022 走看看