socket 的基础知识(一)

来源:互联网 发布:java sendmail 发邮件 编辑:程序博客网 时间:2024/06/05 08:13

Socket  编程

 

计算机网络是相互连接的独立自主的计算机的集合,最简单的网络形式由两台计算机组成


IP地址

IP网络中每台主机都必须有唯一一个IP地址

IP地址是一个逻辑地址

因特网上的IP地址具有全球统一性

32位,4个字节,常用点分十进制的格式表示 192.168.0.23

协议:

为进行网络中的数据交换(通信)而建立的规则,标准或者约定

不同层有各自不同的协议

OSI七层

应用层 :处理网络应用

表示层 : 数据表示

会话层 : 主机间通信

传输层 :端到端的连接

网络层 : 寻址和最短路径

数据链路层 :介质访问

物理层 :二进制传输

OSI 各层所使用的协议

应用层:

远程登陆协议  Telent

文本传输协议   FTP

超文本传输协议 HTTP

域名服务       DNS

简单邮件传输协议 SMTP

邮局协议     POP3

传输层

传输控制协议:TCP

用户数据报协议:UDP

TCP:面向连接的可靠的传输协议

UDP:是无连接的,不可靠的传输协议

 

 

 

网络层

网际协议IP, Internet 互联网控制报文协议ICMP Internet 组管理协议IGMP

 

 

数据封装:一台计算机要发送数据到另一台计算机上,数据首先必须打包,打包的过程称为i封装。 封装就是在数据前面加上特定的协议头部

TCP/IP模型

包括四个层次:应用层,传输层,网络层,网络接口






端口:

传输层提供进程通信的能力,为了标识通信实体中进行通信的进程,TCP/IP协议提出了协议端口,简称端口

端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区),应用程序通过系统调用

与某端口建立连接(bind)之后,传输层传给该端口的数据被相应的进程所接收,相应进程发送给传输层的数据都由该端口输出

端口用一个整数型标示符来表示,即端口号,端口号跟协议相关,TCP/IP传输层的两个协议TCP/UDP 是完全独立的两个软件模块,因此各自的端口号也相互独立。

端口号用一个16位的数字表示,范围是0--65535

 

 

套结字(socket的引入)

Socket 使程序员可以很方便的访问TCP/IP,从而开发各种网络应用的程序

网络字节顺序:

不同的计算机存放多字节值的顺序不同,基于Intel CPU,即我们常用的pc机采用的是

低位先存,为保证数据的正确性,在网络协议中需要指定网络字节顺序,TCP/IP协议使用16位整数和32位整数的高位先存格式

客户端和服务器模式

1.在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户端/服务器模式,客户端向服务器提出请求,服务器接收到请求时,提供相应的服务

2.建立网络的起因:

(1)网络中软硬件资源,运算能力和信息不均等,需要共享,从而造就众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用

(2)网络间的通信完全是异步的,相互通信的进程间不存在父子关系,又不存在共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步。

客户端/服务器模式在操作过程中采用的是主动请求的方式

首先服务器方要先启动,并根据请求提供相应的服务

1.打开一通道并告知本地主机,它愿意在某一公认地址接收客户请求;

2.等待客户请求到达该端口

3.接收到重复请求服务,处理该请求并发送应答信号,接收到并发服务请求,要激活一新的进程来服务处理这个客户请求,新进程处理此客户请求,并不需要对其他请求作出应答,服务完成后,关闭此进程与客户的通信链路,并终止

4.返回第二步,等待另一客户请求

5.关闭服务器

客户端:

1.打开一通信通道,并连接到服务器所在的主机的特定端口

 

2.向服务器发送服务请求报文,等待并接收应答,继续提出请求

3.请求结束 后关闭通信通道并终止

 

 

总结:

1.服务器与客户端的进程的作用是非对称的,因此编码不同

2.服务进程一般是先于客户请求而启动的,只要系统运行,该服务 进程一直存在,直到正常或者被强迫终止

 

 

套接字的类型:

1.流式套结字(SOCK_STREAM

提供面向连接,可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收

内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制,文件传输协议(FTP

用流式套接字

2.数据报套接字(SOCK_DGRAM

提供无连接服务,数据包以独立包形式发送,不提供无错保证,数据可能重复或者丢失,并且接收顺序可能混乱,网络文件系统(NFS)使用数据报式套接字

 

3.原始套接字(SOCK_RAW

该接口允许对于较低层协议,如IPICMP 直接访问,常用于检验新的协议实现或访问现有服务中配置的新设备

基于TCPsocket 编程

服务器:

1.创建套接字(socket

2.将套接字绑定到一个本地地址和端口上(bind

3.将套结字设置为监听模式,准备接收客户请求(listen

4.等待客户端请求哦到来;当请求到来后,接收连接请求,返回一个对此次连接新的套接字(accept

5.用返回的新的套接字与客户端进行通信

6.返回,等待另一用户请求

7.关闭套接字

 

客户端操作

1.创建套接字(socket

2.向服务器发出连接请求(connect

3.和服务器端进行通信(send/recv

4.关闭套接字


基于UDPsocket

服务器:

1.创建套接字(socket

2.J将套接字绑定到一个本地地址和端口上(bind

3.等待接收数据(recvfrom

4.关闭套接字

 

 

客户端:

1.创建套结字(socket

2.向服务器发送数据(sendto

3.关闭套接字

基于套接字系统调用

创建套结字--------socket()

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

第一个参数指定通信发生的区域,UNIX系统支持的地址族有:AF_UNIX  AF_INET

AF_US DOS, WINDOWS 中支持AF_INET

它是网际网区域,因此,地址族与协议族相同

第二个参数是要创建的套接字的类型

第三个参数说明该套接字使用的协议,如果调用者不希望特别指定使用的协议,则置为0

 

使用默认的连接模式 ,根据这三个参数建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。

 

指定本地地址-------bind()

当一个套接字用socket()创建之后,存在一个名字空间(地址族),但它没有被命名,bind()将套接字地址与所创建的套接字号联系起来,即将名字赋与套接字,以指定本地半相关。

#include <sys/types.h>          /* See NOTES */

       #include <sys/socket.h>

 

       int bind(int sockfd, const struct sockaddr *addr,

                socklen_t addrlen);

 

 

第一个参数是socket()调用返回的并且未作连接的套接字描述符

 第二个参数是赋给套接字s的本地地址,其长度可变,结构随通信域的不同而不同。

第三个参数表示第二个参数的长度

 

如果没有发生错误,bind()返回0,否则返回SOCKET_ERROR

 

地址在建立套结字通信过程中起着重要作用,作为一个网络应用程序设计者对套接字地址结构必须有明确认识,

TCP/IP协议的地址结构为:

struct sockaddr_in{

      short sin_family;                 /*AF_INET*/

      u_short sin_port;                 /*16位端口号,网络字节顺序*/

      struct in_addr sin_addr;    /*32IP地址,网络字节顺序*/

      char sin_zero[8];                 /*保留*/

};

sin_family表示地址族,对于IP地址,sin_family成员将一直是AF_INET

sin_port指定的是将要分配给套接字的端口

sin_addr给出的是套接字的主机IP地址

sin_zero只是一个填充数,以使sockaddr_in结构和sockaddr结构的长度一样

如果这个函数调用成功,它将返回0。如果调用失败,这个函数就会返回一个SOCKET_ERROR,错误信息可以通过WSAGetLastError函数返回。

 

 

建立套结字连接-------connect()accept()

Connect()用于建立连接,无连接的套接字进程也可以调用connect,但这时在进程之间没有实际的报文交换,调用将从本地操作系统直接返回。

 

Connect:

int connect(int sockfd, const struct sockaddr *addr,

                   socklen_t addrlen);

第一个参数是欲建立连接的本地套接字描述符

第二个参数说明对方套接字地址结构的指针

第三个参数说明对方套接字的长度

 

 

 

调用成功返回0.失败返回SOCKET_ERROR

在面向连接的协议中,该调用导致本地系统与外部系统之间连接实际建立

 

accept()系统调用

#include <sys/types.h>          /* See NOTES */

       #include <sys/socket.h>

 

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

 

accept面向连接服务器,后面两个参数存放客户端的地址信息,调用前,参数addr指向一个初始值为空的地址结构,addrlen 的初始值为0,调用后,服务器从编号为sockfd的套接字上接受客户连接请求,而连接请求是客户端的connect()调用发出的,当有连接请求到达时,accept()调用将请求连接队列上的第一个客户端套接字地址及其长度放入addraddrlen并创建一个与sockfd有相同特性的新的套接字号,新的套接字可用于 处理服务器并发请求。

监听连接------listen()

此系统调用面向服务器,表示它愿意接收连接

Listen()要在accept()之前调用

int listen(int sockfd, int backlog);

第一个参数表示本地已经建立,尚未连接的套接字号,服务器愿意从上面接收请求

第二个参数表示请求连接队列的最大长度,用于限制监听队列请求的个数,目前允许的最大值为5

调用成功返回0,调用失败:SOCK_ERROR

 

在执行调用时可为没有调用bind()的套接字完成所必须的连接,并建立长度为第二个参数的请求队列

Socket()

bind()

Listen()

accept()

 

 

数据传输:

send()   recv()/  sendfrom   recvfrom

当一个连接建立以后,就可以传输数据了:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

 

 

第一个参数为已连接的本地套接字描述符,

第二个参数buf 是指向存有发送数据的缓冲区的指针

第三个参数长度指定缓冲区的长度

第四个指定传输方式:如是否发送带外数据

 

 

调用成功返回总共发送的字节数,否则返回SOCKET_ERROR

 

 

Recv()函数调用:

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

 

 

 

第一个参数:已经连接的套结字描述符

第二个参数:指向接收输入数据缓冲区的指针

第三个参数:接收数据的长度

第四个参数:指定控制方式:如是否接收带外数据

 

 

调用成功:返回接收的总字节数

连接被关闭:返回0

否则:返回SOCKET_ERROR

Socket()指定五元组中的协议元,它的用法与是否为客户端或者服务器,是否面向连接无关。

bind()指定五元组中的本地二元:本地的主机地址和端口号,它的用法与面向连接有关

在服务器方,无论是否面向连接,均要调用bind()

在客户端方,若采用面向连接,可以不调用bind(),通过connect自动完成,若采用无连接,

客户端必须时用bind()以获取一个唯一的地址

这些仅仅是对于客户端/服务器模式而言,实际上套结字的使用是非常灵活的。

后面我还会再写关于socket的知识,这是第一篇~~~~~

 

 

 

 

 

 

 







原创粉丝点击