1、相关理论:

部分理论资料来自TCP/IP sockets编程(C语言实现),额外做了许多补充。

概念:

IP
每台主机的IP地址都是不同的。主机的IP地址公网IP内网IP。在局域网中,每台主机的IP都取自192.168.1.1-192.168.1.255C类)之间,不存在两台主机的IP重复,此IP是局域网的内网IP,由用户自行分配。公网IP是访问互联网的IP,每次联机到互联网时会随机分配,互联网上的每一台主机的公网IP都不重复。内网IP通过交换机或路由器搭配主机构建,而公网IP是由运营商运营,作用在ADSL设备上。查看内网IP时,通过主机终端执行命令ifconfig(Linux)\ ipconfig(Windows)查看,上面显示的IP就是主机在当前路由的局域网中的IP。而公网IP则可以通过百度搜索IP地址获取,如我当前使用的主机的公网IP内网IP

协议
是关于由通信程序交换的分组及其含义的协定。TCP/IP协议族中的主要协议是IP(网络协议)TCP(传输控制协议)UDP(用户数据报协议),两者的共同功能:寻址

TCP
TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

数据帧格式
(1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1
(3)标志位:共6个,即URGACKPSHRSTSYNFIN等,具体含义如下:
(A)URG:紧急指针(urgent pointer)有效。
(B)ACK:确认序号有效。
(C)PSH:接收方应该尽快将这个报文交给应用层。
(D)RST:重置连接。
(E)SYN:发起一个新连接。
(F)FIN:释放一个连接。

来自:https://blog.csdn.net/sssnmnmjmf/article/details/68486261

UDP
UDP(用户数据报协议)是一种面向事务、简单不可靠信息传送、基于数据报的传输层通信协议。

填充字节表示如果数据长度为奇数,数据就长度加1。

局域网中数据流动图:

数据流向:从应用程序开始,通过TCPIP的实现,通过网络,并在另一端通过IPTCP的实现进行备份。

TCPUDP使用端口号来确定主机内的应用程序。TCPUDP被称为端到端的传输协议,因为它们自始至终把数据从一个程序运送到另一个程序(而IP只把数据从一台主机运送到另一台主机)

TCP的可靠传输
TCP被设计成在IP提供的主机到主机信道中检测可能发生的丢失复制分组及其他错误,并从中恢复过来。TCP提供了可靠的字节流信道,因此应用程序不需要处理这些问题。它是面向连接的协议:在把它用于信道之前,两个程序必须先建立一条TCP连接,这涉及在两台通信的计算机上的TCP实现之间完成握手消息的交换。使用TCP在许多方面也类似于文件输入\ 输出I/O)。

TCP确保可靠传输的机制
(1)校验和
(2)序列号
(3)确认应答
(4)超时重传
(5)连接管理
(6)流量控制
(7)拥塞控制
其实都是计算机网络课教过的东西,如果忘记了,具体原理和过程可以参考:https://blog.csdn.net/liuchenxia8/article/details/80428157

TCP的三次握手建立连接和四次挥手断开连接原理可以参考:https://www.cnblogs.com/Andya/p/13291686.html

UDP的不可靠传输
TCP不同,UDP不会尝试从IP经历的错误中恢复,它只是扩展IP“尽力而为”的数据报服务,使得它在应用程序之间(而不是主机之间)工作。因此,使用UDP的应用程序必须准备好处理分组重新排序等问题的方法和预备程序。

客户与服务器
客户程序发起通信,而服务器程序则被动地等待,然后响应联系它的客户端。客户端与服务器一起组成了应用程序。客户与服务器描述了一种典型的情况,其中服务器使一种特定的能力(如数据库服务)可供能够与之通信的任何客户使用。

套接字:
套接字(socket)是一个抽象层,应用程序可以通过它发送和接收数据,其方式与打开文件句柄允许应用程序读、写数据到稳定的存储器非常相似。套接字允许应用程序插入到网络中,并与插入到同一网络中的其他应用程序通信。由一台机器上的应用程序写到套接字中的信息可以被不同机器上的应用程序读取,反之亦然。

以下部分关于套接字的资料来自:https://blog.csdn.net/daaikuaichuan/article/details/83061726

套接字的类型:流套接字(SOCK_STREAM):提供面向连接、可靠的数据传输服务,对应TCP。数据报套接字(SOCK_DGRAM):数据报套接字提供了一种无连接的服务,对应UDP。原始套接字(SOCK_RAW)。

三种套接字的区别:原始套接字可以读写内核没有处理的IP数据包,流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。如果要访问其他协议发送数据必须使用原始套接字。

套接字缓冲区
每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区输出缓冲区
write() / send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。反过来想,write()函数返回1并不代表发送成功,只是将数据写入缓冲区写入成功了。
read() / recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。

注:
(1)I/O缓冲区在每个TCP套接字中单独存在;
(2)I/O缓冲区在创建套接字时自动生成;
(3)即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
(4)关闭套接字将丢失输入缓冲区中的数据。

2、函数的使用:

以下大部分资料来自:http://c.biancheng.net/view/2344.html做了一些补充。

(1)socket()

函数原型:

int socket(int af,int type,int protocol);

作用:
创建套接字。

参数:
fa
af 为地址族(Address Family),也就是 IP 地址类型。常用的的协议簇:AF_INET(IPv4)AF_INET6(IPv6)AF_LOCAL(UNIX协议)AF_ROUTE(路由套接字)AF_KEY(秘钥套接字)

type
数据传输方式、套接字类型,常用的套接字的类型:SOCK_STREAM(字节流套接字、面向连接套接字)SOCK_DGRAM(数据报套接字、无连接的套接字)

protocol
标识传输协议,常用的有IPPROTO_TCP(TCP传输协议)IPPTPTP_UDP(UDP传输协议),如果此参数设为0,系统会自动识别使用的协议:TCP面向连接,UDP无连接,所以系统可以通过type参数识别协议。

使用:

//TCP (面向连接的)
int tcp_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//UDP (无连接的)
int udp_sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

windows中使用:

int SOCKET socket(int af, int type, int protocol);

(2)bind()

函数原型:

int bind(int sock, struct sockaddr *addr, socklen_t addrlen);

作用:
套接字绑定IP和端口。

参数:
sock
socket函数返回的套接字描述符。

addr
是指向本地IP地址的结构体指针。

addrlen
结构长度。

结构体:

struct sockaddr{unsigned short sa_family; //通信协议类型族AF_xxchar sa_data[14];  //14字节协议地址,包含该socket的IP地址和端口号};
struct sockaddr_in{short int sin_family; //通信协议类型族unsigned short int sin_port; //端口号struct in_addr sin_addr; //IP地址unsigned char si_zero[8];  //填充0以保持与sockaddr结构的长度相同};
struct in_addr{in_addr_t  s_addr;  //32位的IP地址
};

sockaddrsockaddr_in的长度相同,都是16字节,只是将IP地址和端口号合并到一起,用一个成员 sa_data表示。要想给 sa_data赋值,必须同时指明IP地址和端口号。sockaddr是一种通用的结构体,可以用来保存多种类型的IP地址和端口号,而 sockaddr_in是专门用来保存 IPv4地址的结构体。

用来存放ipv6地址的结构体:

struct sockaddr_in6 {sa_family_t sin6_family;  //(2)地址类型,取值为AF_INET6in_port_t sin6_port;  //(2)16位端口号uint32_t sin6_flowinfo;  //(4)IPv6流信息struct in6_addr sin6_addr;  //(4)具体的IPv6地址uint32_t sin6_scope_id;  //(4)接口范围ID
};

使用时的代码:

//创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//创建sockaddr_in结构体变量
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
serv_addr.sin_family = AF_INET;  //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址,本地
serv_addr.sin_port = htons(8000);  //端口
//将套接字和IP、端口绑定
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

windows中使用:

int bind(SOCKET sock, const struct sockaddr *addr, int addrlen);

(3)connect()

函数原型:

int connect(int sock,struct sockaddr *serv_addr,socklen_t addrlen);

作用:
建立到达服务器的连接。

参数:(参数与bind()一样)

sock
socket函数返回套接字描述符。

serv_addr
服务器IP地址结构指针。

addrlen
结构体指针的长度。

windows中使用:

int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen);

(4)listen()

函数原型:

int listen(int sock, int backlog)

作用:
通过isten()函数可以让套接字进入被动监听状态。

参数:
sock
sock为需要进入监听状态的套接字。

backlog
设置可连接客户端的最大连接个数,即请求队列。当有多个客户端向服务器请求时,收到此值的影响。当设该参数为SOMAXCONN时,会让系统来决定请求队列的长度。

被动监听:
指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。

请求队列:
当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。如果不断有新的请求进来,它们就按照先后顺序在缓冲区中排队,直到缓冲区满。这个缓冲区,就称为请求队列(Request Queue)
当请求队列满时,就不再接收新的请求,对于 Linux,客户端会收到 ECONNREFUSED错误,对于 Windows,客户端会收到 WSAECONNREFUSED错误。

windows中的使用:

int listen(SOCKET sock, int backlog);

注意:
listen()只是让套接字处于监听状态,并没有接收请求。接收请求需要使用 accept()函数。

(5)accept()

函数原型:

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);

作用:
当套接字处于监听状态时,可以通过 accept()函数来接收客户端请求。

参数:
sock
服务器端套接字。

addr
sockaddr_in结构体变量。

addrlen
参数 addr的长度,可由 sizeof()求得。

windows中使用:

SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);

注:
listen()只是让套接字进入监听状态,并没有真正接收客户端请求,listen()后面的代码会继续执行,直到遇到 accept()accept()会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。

(6)write()

函数原型:

ssize_t write(int fd, const void *buf, size_t nbytes);

作用:
向套接字中写入数据。

参数:
fd
要写入的文件的描述符。

buf
要写入的数据的缓冲区地址。

nbytes
要写入的数据的字节数。

注:
两台计算机之间的通信相当于两个套接字之间的通信,在服务器端用 write()向套接字写入数据,客户端就能收到,然后再使用 read()从套接字中读取出来,就完成了一次通信。

windows中的使用:
windows下使用的是send()

int send(SOCKET sock, const char *buf, int len, int flags);

(7)read()

函数原型:

ssize_t read(int fd, void *buf, size_t nbytes);

作用:
read()函数会从 fd文件中读取 nbytes个字节并保存到缓冲区buf,成功则返回读取到的字节数(但遇到文件结尾则返回0),失败则返回 -1

参数:
fd
要读取的文件的描述符。

buf
要接收数据的缓冲区地址。

nbytes
要读取的数据的字节数。

windows中的使用:
windows下使用的是recv()

int recv(SOCKET sock, char *buf, int len, int flags);

(8)inet_addr()

函数原型:

in_addr_t inet_addr(const char* strptr);

作用:
将字符串形式的IP地址,转为网络字节序的整型。

参数:
字符串型地址,如:“192.168.1.5”

(9)inet_ntoa()

函数原型:

char *inet_ntoa(struct in_addr in);

作用:
将网络字节序的整型值转为字符串型的IP地址。

(10)memset()

函数原型:

extern void *memset(void *buffer, int c, int count)

作用:
使用某个值填充数组或指针。

参数:
buffer
等待填充的数组或指针。

c
填充的值。

count
buffer中填充的长度。

使用:

//把buffer数组,所有元素置0
memset(buffer, 0, sizeof(buffer))

linux c socket编程学习(1)(一些基本概念及基本的函数使用)相关推荐

  1. asp.core api 通过socket和服务器通信发送udp_详解Linux的SOCKET编程

    文章来自于 https://www.zhangshengrong.com/p/9Oabd95XdK/ PHP进阶学习交流QQ群:983229225 本篇文章对Linux的SOCKET编程进行了详细解释 ...

  2. socket编程学习(addr设置)

    sockaddr结构体 struct  sockaddr{ sa_family_t  sa_family; //地址族,最常用的是"AF_INET"(IPV4)和"AF_ ...

  3. Linux下Socket编程

    Linux下Socket编程    网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符.Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的S ...

  4. linux系统udp通信程序,Linux UDP socket编程(UDP通讯模型) | C/C++程序员之家

    Linux UDP socket编程(UDP通讯模型): UDPClient + UDPService. Linux下大多数网络程序都是基于TCP的,很少基于UDP,简单的通讯模型如下,开发时候备用! ...

  5. Linux的SOCKET编程 简单演示

    转载:http://blog.csdn.net/hguisu/article/details/7445768/ Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源 ...

  6. 一文了解linux下socket编程

    一文了解linux下socket编程 文章目录 一文了解linux下socket编程 1 网络编程的相关简述 1.1 引言 1.2 Tcp和Udp简介 1.3 TCP三次握手和四次挥手 1.4 网络编 ...

  7. LINUX下Socket编程 函数格式详解

    你需要了解的一些系统调用: socket() bind() connect() listen() accept() send() recv() sendto() recvfrom() close() ...

  8. Linux的SOCKET编程详解

    Linux的SOCKET编程详解 一. 网络中进程之间如何通信 进程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系统 ...

  9. linux下socket编程中setsockopt的作用

    如题所示,在linux进行socket编程的时候,一般而言,socket,bind,listen三步曲之后,就开始接收客户端请求,然后实现收发数据. 如下所示的代码,是没有setsockopt的情况: ...

最新文章

  1. 希尔排序——算法系列
  2. java获取当前路径
  3. 详解|清华大学100页PPT:工业机器人技术详解
  4. hdu1863 畅通工程---MST连通
  5. perl 取出目录中的所有文件并存入文件中
  6. 对oracle静态参数修改一点研究
  7. 五分钟了解先验概率和后验概率
  8. FreeBSD与Linux的比较
  9. 加减法叫做什么运算_【课堂实录】加减法运算的本质(四上)
  10. CCPC-Wannafly Winter Camp Day3 (Div2, onsite) I 石头剪刀布(按秩合并并查集)
  11. [KALI] 开启ssh远程连接
  12. Cisco路由器配置静态路由
  13. Java 后台做图片压缩的两种方法
  14. java-IO-字节数组输入输出流(ByteArrayInputStream、ByteArrayOutputStream)
  15. 3D游戏——AR图片识别与建模
  16. C 实现Mysql增量备份_mysql增量备份 - lyle_luo的个人页面 - OSCHINA - 中文开源技术交流社区...
  17. Nexus搭建Maven私服全攻略一:认识Nexus与索引
  18. Python与rrdtool的结合模块
  19. 【GDOI 2016 Day1】疯狂动物城
  20. c语言托儿所收2到6岁儿童,2018下教师资格考试测试试题:幼儿《保教知识与能力》(三)...

热门文章

  1. 云和恩墨大讲堂 - 海南站
  2. 论文笔记-DeepLung: Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification
  3. 天气预报查询数据接口、实时天气、24小时天气、未来24小时、7天/15天预报
  4. [转]多媒体封装格式详解---MP4
  5. SpringBoot整合Redis实现缓存、队列、广播
  6. 不是所有产品都适合做亚马逊CPC广告
  7. 移动H5前端性能优化指南(转自ISUX)
  8. 3d打印机打印obj格式_购买3D打印机如何为您省钱
  9. 实例6:圆周率的计算
  10. List size为1但是内容为null处理方法