TCPIP网络编程

1 网络编程和套接字的概念

1.1 概要

网络编程:编写程序使两台连网的计算机相互交换数据,利用操作系统提供的套接字进行编程,又称套接字编程

套接字:表示两台计算机之间的网络连接

创建服务器端套接字的过程如下:

  • 创建一个套接字,套接字是由**socket()**函数生成的
#include<sys/socket.h>
int socket(int domain, int type, int protocol);

//执行成功时返回文件描述符file_description,失败时返回-1

  • 使用**bind()**给创建好的套接字分配地址信息(IP地址和端口号)
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
//成功时返回0,失败时返回-1
  • 使用**listen()**将套接字转为可接听状态
int listen(int sockfd, int backlog);
//成功时返回0,失败时返回-1
//sockfd:希望进入等待连接请求状态的套接字文件描述符,传递的描述符套接字参数成为服务器端套接字
//backlog:连接请求等待队列的长度,若为5,则队列长度为5,表示最多使5个连接请求进入队列
  • 当其他主机请求连接时,调用**accept()**函数处理
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//成功时返回file_description,失败时返回-1
//sockfd:服务器套接字的文件描述符
//addr:保存发起连接请求的客户端地址信息的变量地址,调用函数后向传递来的地址变量参数填充客户端地址信息
//addrlen:第二个参数addr结构体的长度,但是存有长度的变量地址。函数调用完成后,该变量即被填入客户端地址长度

创建客户端套接字的过程较为简单,只有调用socket()函数创建套接字和调用connect()函数向服务器端发送连接请求这两个步骤,connect()的函数原型如下:

int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);
//成功时返回0,失败时返回-1

1.2 Linux文件操作

文件描述符:系统分配给文件或套接字的整数,其存在的意义在于成为程序员与操作系统之间良好沟通的渠道,其只不过是为了方便称呼操作系统创建的文件或套接字而赋予的数

接下来介绍文件的基本操作

  • 打开文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcnt1.h>

int open(const char *path, int flag);
//path表示打开的目标文件名及路径信息,flag是文件打开模式,打开模式的具体宏定义在P11有详细说明
//成功时返回file_description,失败时返回-1
//冷知识open()与socket()返回的文件描述符没有任何区别
  • 关闭文件
#include<unistd.h>

int close(int fd);
//成功时返回0,失败时返回-1

值得注意的是,close()函数不仅可以用来关闭文件,还可以关闭套接字,这再次证明了Linux操作系统不区分文件和套接字的特点!

  • 将数据写入文件
ssize_t write(int fd, const void *buf, size_t nbytes);
//成功时返回写入的字节数,失败时返回-1
//buf一般是一个char数组,

size_t是通过typedef声明的unsigned int类型;ssize_t是通过typedef声明的signed int类型

操作系统定义的数据类型会添加后缀_t,如size_t,ssize_t都是源数据类型(primitive),包含在sys/types.h头文件中

  • 读取文件中的数据
ssize_t read(int fd,void *buf, size_t nbytes);
//成功时返回接收的字节数(但遇到文件结尾则返回0),失败时返回-1

1.3 基于Windows平台的实现

初始化winsock的公式

int main(int argc, char* argv[])
{
   
    WSADATA wsaData;
    //.....
    if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
        ErrorHandling("WSAStartup() error");
    //.....
    WSACleanup();
    return 0;
}

Clion动态链接win_sock32的解决办法

在Clion项目自带的CMakeLists中添加一行link_libraries(ws2_32),注意不要再add_executable之后添加,而是在其之前添加!

Windows中严格区分文件I/O函数和套接字I/O函数,所以在使用上与Linux有些不同

创建socket套接字的函数:

#include<winsock2.h>

SOCKET socket(int af, int type, int protocol);
//成功时返回socket句柄,失败时返回INVALID_SOCKET
//SOCKET结构体用来保存整数型套接字句柄值,即整数数据

2 套接字类型与协议设置

**socket()**函数中具体的参数对应的含义:

#include<sys/socket.h>

int socket(int domain, int type, int protocol);
//domain:套接字中使用的协议族信息
//type:套接字数据传输类型信息
//protocol:计算机间通信中使用的协议信息
//通过domain参数决定protocol参数决定最终使用的协议信息

协议族分类、套接字类型的具体功能见书本P27

3 地址族与数据序列

3.1 IP地址与端口号

A类地址:0~127,首位以0开始

B类地址:128~191,首两位以10开始

C类地址:192~223,首三位以110开始

得知了IP地址能够向目标主机传输数据,但是仅凭这些无法传输给最终的应用程序,这时我们需要知道应用程序所对应的端口号,即端口号是用来区分同一台主机上的不同套接字的依据

不同类型的套接字可以共用一个端口号,如TCP套接字与UDP套接字都可以使用8080端口,但是两个TCP套接字不能共用相同的端口

3.2 地址信息的表示

地址信息在编程中用下面两个结构体表示

struct sockaddr_in
{
   
    sa_family_t 	sin_family; //地址族
    uint16_t 		sin_port;//端口号
    struct in_addr 	sin_addr;//IP地址
    char 			sin_zero[8];//不使用
}
struct in_addr
{
   
    in_addr_t		s_addr;//32位IP地址
}

sin_zero只是为了结构体sockaddr_in的大小与sockaddr结构体保持一致而插入的成员。

struct sockaddr
{
   
    sa_family_t sinfamily;//地址族
    char		sa_data[14];//地址信息
}

bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)),其中第二个参数期望的到sockaddr结构体变量地址值,所以直接对sockaddr_in结构体变量地址值做一个强制类型转换即可得到!

3.3 网络字节序

由于不同CPU使用的字节序可能不同(大端、小端,计算机的大小端与CPU有关,Inter与AMD的CPU都采用小端),故通过网络传输数据时约定统一方式,即统一为大端,这就是网络字节序

字节序转换的函数

unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned short htonl(unsigned long);
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值