前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络编程基础第二讲.网络编程框架

网络编程基础第二讲.网络编程框架

作者头像
IBinary
发布2019-05-25 16:48:37
5090
发布2019-05-25 16:48:37
举报
文章被收录于专栏:逆向技术逆向技术逆向技术

        网络编程基础第二讲.网络编程框架

一丶了解的知识

  1.什么是socket

     socket 是开发接口.是TCP/IP网络环境下.应用程序与驱动程序之间访问的接口.

  2.服务跟类型

    socket服务 分为面向连接跟无连接,代表的协议就是TCP/IP

    socket类型: 有三种类型

      SOCK_STREAM 流式套接字. 可靠的套接字.可以处理大量数据.不会丢包.但是开销比大. 代表就是TCP协议. 是在传输层上做的.

      SOCK_DGRAM 数据报套接字.不可靠.允许丢包. 常用与音频.视频等等. 代表就是UDP协议.

      SOCK_RAW 原始套接字. 是在网络层进行编程的.也就是对底层的IP可以进行编程.不过常用的就是前边两种.

  3.构建Windows框架.

  4.IP地址的表现形式.

  5.编写一个简单的网络程序. TCP模型.

二丶构建Windows框架

  在windows下使用socket需要使用windows初始化函数.还要包含库文件.

#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

以及使用API进行初始化

 WSADATA data;
 WSAStartup(MAKEWORD(2, 2), &data);

WSAStartup(版本号,执行成功会返回一个WSADATA结构)

版本号使用MAKEWORD即可.我们现在使用的是2版本. 其实就是 高位低位都为2 0x0202这个值.

返回值:

    0成功

    1失败;

完整代码:

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
    WSADATA data;
    if (WSAStartup(MAKEWORD(2, 2), &data))
    {
        puts("对不起初始化失败\r\n");
        system("pause");
    }
    getchar();

    return 0;
}

三丶IP地址表现形式

 IP地址常用点分法来表示 也就是用点隔开. 用4个 0到255之间的整数来表示

例如:

  192.168.0.0.1

但是在计算机中.不使用 点分法来保存IP地址. 这样会浪费存储空间.而且.不便计算 子网掩码.

我们知道 子网掩码 跟IP地址是and的关系. 所以不使用这个.

1.网络字节序

  在网络传送中,IP地址会保存为32位的二进制数.

  低位存储地址中保存数据的高位字节.高位中存储低位字节. 也就是我们常说的大端模式.

小端模式:高地址存储高位,低地址存储低位

  0x12345678 地址放高位. 高地址放低位 例如: 78 56 34 12 我们的高地址存储了12 依次类推.

大端模式:

    高地址存放低位, 低地址存放高位.

 0x 12345678 在内存中表现形式 12 34 56 78

这个就是大端模式.

VC中 in_addr 来保存IP地址. 对应的转化则是 inet_addr 跟 inet_ntoa

示例代码如下:

 in_addr addr;

 addr.S_un.S_addr = inet_addr("127.0.0.1");  //保存我们的IP地址.需要进行转换.
typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;  s_b1 ,s_b2 就是保存着我们的IP地址.点分法表示.
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;

转换回来:

  使用 inet_ntoa(addr)即可.

 char *pszIp = NULL;
   pszIp = inet_ntoa(addr);

代码调试截图:

2.主机字节顺序

  什么是主机字节顺序.主机字节顺序就是指不同的主机在堆IP地址进行存储的时候.使用的格式不同.

所以需要通过函数进行转换.

  htonl() 将主机字节顺序格式的IP地址转化成为TCP/IP网络字节顺序

  htons 主机转网络.

  ntohl 网络转主机

  ntohs 网络转主机.

h 主机的意思 to 转化的意思 n 网络的意思 network l 就是 ulong

所以根据缩写就能明白什么意思.

四丶客户端服务端编写流程以及代码

如下图可以清楚看到顺序

有点复杂的就是服务端(主机).他要绑定本地.并且接受连接.也就是说客户端只要连接.就会有一个Socket

我们对这个socket操作.就能实现主机跟客户端的通信了.

当有多个客户端连接的时候.我们就要保存socket了. 这个以后会讲到.也就是可能会接触到各种各样的模型.

来进行处理.

需要用到的函数解析

1.socket 创建socket

socket (协议家族,套接字类型,连接类型)
示例代码:
    socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)
返回一个SOCKET值. windows中定义的是 UINT
失败: INVALID_SOCKET
2.绑定
   sockaddr_in addrserver;
    addrserver.sin_family = AF_INET;
    addrserver.sin_port = htons(8564);//端口必须转换
    addrserver.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//给定IP.如果是这个宏.则可以任何主机都可以连接

    bind(hServer, (sockaddr *)&addrserver, sizeof(addrserver));

绑定的时候.我们要指明绑定的IP.以及绑定的端口.

此时我们会使用一个 sockaddr_in 的结构体.socket中其实真正的结构体是 sockaddr 但是操作不方便.

所以给了一个sockaddr_in的结构体. 大小跟 sockaddr结构体是一样的.

因为使用的是网络字节序. 所以 我们的端口以及IP地址都需要进行转换.

IP地址是 32位的.所以使用 htonl

端口是2个字节.也就是16为. 所以使用 htons

3.监听套接字

 nRet = listen(hServer, 10); //参数1.socket 参数2. 同时监听处理的socket的数量

  if (SOCKET_ERROR == nRet)
  {
      printf("listen 失败\r\n");
      closesocket(hServer);
      WSACleanup();
      goto OPT;
  }

监听就很简单了.我们要指明同时接受的socket以及同时处理的最大socket.所以给定socket 然后给一个数量即可.

4.获取用户的连接请求

  获取用户的连接请求主要是用accept关键字. 给一个socket句柄.然后会把客户端连接这个socket的一系列信息都会记录在结构体中.

并且返回客户端的socket.我们只要对这个socket操作.就能进行操作了.

 SOCKET hClient;
  
  sockaddr_in addrClient;   //保存客户端的addr属性.客户端的IP以及端口都会放在里面
  int nLen = sizeof(addrClient);
  hClient = accept(hServer, (sockaddr *)&addrClient, &nLen);传出结构.以及长度.返回客户端socket

5.对客户端socket进行读取或者写入.

  读取的 API recv

  写入的API send

相应的如果是UDP连接则使用 recvfrom /sendto

 char pszBuffer[1024] = { NULL };
  recv(hClient, pszBuffer, sizeof(char) * 1024, 0);
要对客户端的socket进行读写.所以传入的是客户端的socket

send是一样的.

最后进行关闭套接字即可.

服务端完整代码:

// socket.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
    WSADATA data;
    if (WSAStartup(MAKEWORD(2, 2), &data))
    {
        puts("对不起初始化失败\r\n");
        system("pause");
    }

    in_addr addr;

    addr.S_un.S_addr = inet_addr("127.0.0.1");
    char *pszIp = NULL;
    pszIp = inet_ntoa(addr);
   

    SOCKET hServer;
    hServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == hServer)
    {
        printf("socket 失败\r\n");
        goto OPT;
    }

    //2.绑定在本地
    sockaddr_in addrserver;
    addrserver.sin_family = AF_INET;
    addrserver.sin_port = htons(8564);//端口必须转换
    addrserver.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//给定IP.如果是这个宏.则可以任何主机都可以连接

  int nRet =   bind(hServer, (sockaddr *)&addrserver, sizeof(addrserver));
  if (SOCKET_ERROR == nRet)
  {
      printf("bind 失败\r\n");
      goto OPT;
  }

  //3监听套接字的连接
  nRet = listen(hServer, 10); //参数1.socket 参数2. 同时监听处理的socket的数量

  if (SOCKET_ERROR == nRet)
  {
      printf("listen 失败\r\n");
      closesocket(hServer);
      WSACleanup();
      goto OPT;
  }

  //4.获取用户的数据请求.也就是接受客户端的连接的socket
  SOCKET hClient;
  
  sockaddr_in addrClient;   //保存客户端的addr属性.客户端的IP以及端口都会放在里面
  int nLen = sizeof(addrClient);
  hClient = accept(hServer, (sockaddr *)&addrClient, &nLen);

  //5.接受用户发送的数据
  char pszBuffer[100] = { NULL };
  recv(hClient, pszBuffer, sizeof(char) * 100, 0); //阻塞读取.不读取不返回
  printf("接受到的数据 = %s \r\n", pszBuffer);

OPT:
  closesocket(hClient);  //释放一切资源.
  closesocket(hServer);
  WSACleanup();
    getchar();
    return 0;
}

客户端代码就很简单了.

需要用到一个 connect API. 也就是连接的API. 调用这个API则跟服务端进行连接. 服务端的accept就会返回这个socket.

完整代码.

// socket.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
    WSADATA data;
    if (WSAStartup(MAKEWORD(2, 2), &data))
    {
        puts("对不起初始化失败\r\n");
        system("pause");
    }

   


    //1.创建
    SOCKET hClient;
    hClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == hClient)
    {
        printf("socket 失败\r\n");
        goto OPT;
    }

  
    //2.连接
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");    //指定IP跟端口才能连接
    addr.sin_port = htons(8564);
    connect(hClient, (sockaddr *)&addr, sizeof(addr));//指明服务端信息.才能进行通讯.

    //3.收发数据.
    char pszBuffer[100] = "HelloWorld";
    send(hClient, pszBuffer, sizeof(char) * 100,0);

OPT:
    closesocket(hClient);  //释放一切资源.
    WSACleanup();
    getchar();
    return 0;
}

应用实现截图:

课堂代码:
  链接:https://pan.baidu.com/s/1iKX4cvFdQ9yAnZaIydrQIg 密码:9d0t
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-09-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  •         网络编程基础第二讲.网络编程框架
    • 一丶了解的知识
      • 二丶构建Windows框架
        • 三丶IP地址表现形式
          • 四丶客户端服务端编写流程以及代码
            • 需要用到的函数解析
            • 5.对客户端socket进行读取或者写入.
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档