Socket网络编程(一)

来源:互联网 发布:淘宝客服名字大全 编辑:程序博客网 时间:2024/05/19 06:15

1、Socket的定义

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。

2、网络分层

ISO模型的可以五个分层,也可以七个分层(表示层、会话层、应用层 =  应用层 ),接下来详细介绍五个分层

应用层:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等    --工作:支持网络应用,应用协议仅仅是网络应用的一个组成部分,运行在不同主机上的进程则使用应用层协议进行通信。

传输层:TCP(传输控制协议),UDP(用户数据报协) --工作:负责为信源和信宿提供应用程序进程间的数据传输服务

网络层:IP,ICMP,OSPF,EIGRP,IGMP  --工作:负责将数据报独立地从信源发送到信宿,主要解决路由选择、拥塞控制和网络互联等问题。

数据链路层:SLIP,CSLIP,PPP,MTU  --工作:负责将IP数据报封装成合适在物理网络上传输的帧格式并传输,或将从物理网络接收到的帧解封,取出IP数据报交给网络层。

物理层:--工作:为数据端设备提供传送数据通路、传输数据。

3、Socket的通信流程


4、Socket的作用

套接字主要用来实现进程与进程之间的通信(包括不同主机之间的进程的通信)。

5、Socket的类型(TCP、UDP)

1、流式套接字(TCP)

流式的套接字可以提供可靠的、面向连接的通讯流。如果你通过流式套接字发送了顺序的数据:“1”、“2”。那么数据到达远程时候的顺序也是“1”、“2”。超时重传是TCP协议保证数据可靠性的一个重要机制,其原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成功为止。

SVN包大小64位

 

1、           创建Socket工具(Socket())

2、           给一个进程分配一块内存,数据放到内存里(bind())

3、           一直检查有没有发送数据这个包过来(listen())

4、           接收数据包(accept())

1.1  三次握手

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。

 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

1.2  四次挥手

第一次挥手TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。

第二次挥手服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。

第三次挥手服务器关闭客户端的连接,发送一个FIN给客户端。

第四次挥手客户端发回ACK报文确认,并将确认序号设置为收到序号加1。

1.3  长连接和短连接

短连接的操作步骤:

建立连接-数据传输-关闭连接……..建立连接-数据传输-关闭连接

Http  短连接  


长连接的操作步骤:

连接-数据传输…(保持连接)…数据传输….-关闭连接


长连接和短连接的区别:

长连接传送数据多,但对服务器的压力大,短连接对服务器压力小,但传送数据少


2、数据报套接字

数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。

如果你发送了一个数据报,它可能不会到达。


它可能会以不同的顺序到达。


如果它到达了,它包含的数据中可能存在错误。

 

1、


六、套接字基本结构

struct  sockaddr
{
    unsigned short sa_family;/*address族,AF_INET*/ (short  int  2 字节)
    char sa_data[14];/* IP地址、端口和套接字的数目,它里面的数据是杂溶在一起的*/(14字节)
};

struct sockaddr_in {
    short int sin_family; /* Internet地址族*/(2字节)
    unsigned short int sin_port; /*端口号*/(2字节)
    struct in_addr sin_addr; /* ip地址*/(4字节)
    unsigned char sin_zero[8]; /*添0(和struct sockaddr一样大小)*/(8个字节)
};//一定要保证 sin_port 和 sin_addr 必须是网络字节顺序!


server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(SERVPORT);//1234
server_sockaddr.sin_addr.s_addr=INADDR_ANY;
//INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。
server_sockaddr.sin_addr.s_addr=inet_addr(“166.111.69.52”);//inet_addr()返回的就是网络字节序
bzero(&(server_sockaddr.sin_zero),8);


struct in_addr
{
    unsigned long s_addr;(4字节 32位:正好是现在的IPV4的位数)
};

大端:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
小端:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
网络字节顺序采用大端排序方式。(本机->网络(大端)->另一台电脑)

如果将一个32位的整数0x12345678存放到一个整型变量(int)中,这个整型变量采用大端或者小端模式在内存中的存储由下表所示。为简单起见,使用OP0表示一个32位数据的最高字节,使用OP3表示一个32位数据最低字节。
地址偏移       大端模式        小端模式
0x00          12(op0)       78(op3)
0x01          34(op1)       56(op2)
0x02          56(op2)       34(op1)
0x03          78(op3)       12(op0)

//------------
server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(SERVPORT);//1234
server_sockaddr.sin_addr.s_addr=INADDR_ANY;
//INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。
server_sockaddr.sin_addr.s_addr=inet_addr(“166.111.69.52”);//inet_addr()返回的就是网络字节序
bzero(&(server_sockaddr.sin_zero),8);

/*
htons()——“Host to Network Short”主机字节顺序转换为网络字节顺序(对无符号 短型进行操作 4 bytes)
htonl()——“Host to Network Long” 主机字节顺序转换为网络字节顺序(对无符 号长型进行操作 8 bytes)
ntohs()——“Network to Host Short “ 网络字节顺序转换为主机字节顺序(对无符 号短型进行操作 4 bytes)
ntohl()——“Network to Host Long “ 网络字节顺序转换为主机字节顺序(对无符 号长型进行操作 8 byte
 
 h”开头的(代表“主机”);紧跟着它的是“to”,代表“转换到”;然后是“n” 代表“网络”;最后是“s”,代表“短型数据”。H-to-n-s,就是 htons() 函数(可以使用 Host to Network Short 来助记)
*/

七、套接字函数

#include<sys/types.h>
#include<sys/socket.h>
//创建工具  参数1
//TCP  UDP  参数2 
//写0  参数3

int socket(int domain,int type,int protocol)
domain://协议类型,一般为AF_INET
type://socket类型:SOCK_STREAM(TCP)或者SOCK_DGRAM(UDP)
protocol://是与特定的地址家族相关的协议,如果指定为0,那么系统就会根据地址格式和套接类别,自动选择一个合适的协议.这是推荐使用的一种选择协议的方法.
返回值://如果socket函数调用成功,他就会返回一个新的socket数据类型的套接字描述符;如果调用失败,返回-1

//socket函数的返回值
//sockaddr  sockaddr_in  (操作更方便)
int bind(int sockfd,struct sockaddr *my_addr,int addrlen)
sockfd://socket描述符
my_addr://是一个指向包含有本机IP地址和端口号信息的sockaddr类型的指针
addrlen://常被设置为sizeof(struct sockaddr)
返回值://出错返回-1

int connect(int sockfd,struct sockaddr *serv_addr,int addrlen)
sockfd://目的服务器的socket描述符
serv_addr://包含目的机器IP地址和端口号的指针
addrlen://sizeof(struct sockaddr)
返回值://如果发生了错误(比如无法连接到远程主机,或是远程主机的指定端口无法进行连接等)它将会返回错误值 –1


int listen(int sockfd,int backlog);
sockfd://socket()系统调用返回的socket描述符
backlog://指定在请求队列中的最大请求数.可以将其设成 5 到 10 之间的数值(推荐)。
返回值://返回 –1 ,那么说明在 listen()的执行过程中发生了错误。


int accept(int sockfd,void *addr,int addrlen)
sockfd://是被监听的socket描述符
addr://通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息
addrlen://addrlen 是一个本地的整型数值,在它传给accept()前,它的值应该是sizeof(struct sockaddr_in);大小。accept()不会在addr中存储多余addrlen bytes大小的数据。如果 accept()函数在 addr 中存储的数据量不足 addrlen,则 accept()函数会改变 addrlen 的值来反应这个情况。
返回值://如果调用 accept()失败的话,accept()函数会返回 –1 来表明调用 失败.


int send(int sockfd,const void *msg,int len,int flags)
sockfd://用来传输数据的socket描述符
msg://要发送数据的指针
flags://0
返回值://send()函数在调用后会返回它真正发送数据的长度。注意:send() 所发送的数据可能少于你给它的参数所指定的长度!


int recv(int sockfd,void *buf,int len,unsigned int flags)
sockfd://接受数据的socket描述符
buf://存放数据的缓冲区
len://缓冲的长度
flags://0
返回值://recv() 返回它所真正收到的数据的长度。(也就是存到 buf 中数据的长度)。如果返回 –1 则代表发生了错误(比如网络以外中断、对方关闭了套接字连接等).


int sendto(int sockfd,const void *msg,int len,unsigned int flags,const struct sockaddr *to,int tolen)
sockfd://代表你与远程程序连接的套接字描述符。
msg://一个指针,指向你想发送的信息的地址。
len://你想发送信息的长度。
flags://发送标记。一般都设为 0。
to://一个指向struct sockaddr结构的指针,里面包含了远程主机的IP地址和端口数据。
tolen://只是指出了structsockaddr在内存中的大小sizeof(structsockaddr)。
返回值://sendto()返回它所真正发送的字节数(当然也和 send()一样,它所真正发送的字节数可能小于你所给它的数据的字节数)。 当它发生错误的时候,也是返回 –1。


int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *form,int fromlen)
sockfd://是你要读取数据的套接字描述符。
buf://是一个指针,指向你能存储数据的内存缓存区域。
len://是缓存区的最大尺寸。
flags://是recv()函数的一个标志,一般都为0。
from://一个本地指针,指向一个struct sockaddr的结构(里面存有源IP地址和端口数).
fromlen://是一个指向一个 int 型数据的指针,它的大小应该是 sizeof(struct sockaddr).当函数返回的时候,formlen指向的数据是form指向的struct sockaddr的实际大小.
返回值://返回它接收到的字节数,如果发生了错误,它就返回–1 。

close(sockfd)
//执行 close()之后,套接字将不会在允许进行读操作和写操作。

int shutdown(int sockfd,int how)
how://可以取下面的值。0 表示不允许以后数据的接收操作;1 表示不允许以后数据的发送操作;2 表示和 close()一样,不允许以后的任何操作(包括接收,发送数据) shutdown() 如果执行成功将返回 0,如果在调用过程中发生了错误,它将返回–1。


0 0
原创粉丝点击