石家庄 网站建站,网站建设zgkr,直接下载app,网页游戏入口文章目录 一、SOCKET1、网络套接字SOCKET2、网络字节序2.1、小端法2.2、大端法2.3、字节序转换3、IP地址转换函数3.1、本地字节序转网络字节序3.1.1、函数原型#xff1a;3.1.2、返回值3.2、网络字节序转本地字节序3.2.1、函数原型3.2.2、返回值4、sockaddr地址结构#xff0… 文章目录 一、SOCKET1、网络套接字SOCKET2、网络字节序2.1、小端法2.2、大端法2.3、字节序转换3、IP地址转换函数3.1、本地字节序转网络字节序3.1.1、函数原型3.1.2、返回值3.2、网络字节序转本地字节序3.2.1、函数原型3.2.2、返回值4、sockaddr地址结构服务器server写法4.1、struct sockaddr_in addr4.2、struct sockaddr_in结构体5、socket模型创建流程分析6、socket和bind6.1、socket6.1.1、socket函数6.1.2、返回值6.2、bind6.2.1、bind函数7、listen和accept7.1、listen7.1.1函数原型7.1.2、返回值7.2、accept7.2.1、函数原型7.2.2、返回值8、connect函数client8.1.1、函数原型8.1.2、返回值二、TCP通信案例1、TCP通信模型1.1、需求分析1.2、功能简介2、步骤分析与代码2.1、server2.1.1、步骤分析2.1.2、server.c代码2.2、client2.2.1、步骤分析2.2.2、client.c代码三、三次握手 和四次挥手1、三次握手2、数据通信三次握手之后3、四次挥手关闭连接 一、SOCKET
1、网络套接字SOCKET
1一个文件描述符指向一个套接字该套接字内部由内核借助两个缓冲区实现 2在通信过程中套接字一定是成对出现的
2、网络字节序
2.1、小端法
计算机本地存储高位存高地址低位存低地址
2.2、大端法
网络存储高位存低地址低位存高地址
2.3、字节序转换
为了能使计算机和网络之间能够顺利通信需要进行字节序的转换就是大小端之间的转换,l表示32位无符号整型s表示16位短整型h代表host主机n代表net网络 1htonl—》本地—》网络IP 2htons—》本地—》网络port端口号 3ntohl—》网络—》本地IP 4ntohs—》网络—》本地port
3、IP地址转换函数
3.1、本地字节序转网络字节序
3.1.1、函数原型
Int inet_pton(int af,const char*src,void *dst)//本地字节序string IP—》网络字节序 1af:AF_INET、AF_INET6 2src传入IP地址点分十进制 3dst传出转换后的网络字节序的IP地址
3.1.2、返回值
成功1 异常0说明src指向的不是一个有效的IP地址 失败-1
3.2、网络字节序转本地字节序
3.2.1、函数原型
Const char *inet_ntop(int af,void *src,char *dst,socklen_t,size);//网络字节序—》本地字节序string IPaf:AF_INET、AF_INET6 src网络字节序IP地址 dst转换后的本地字节序字节序的IP地址string IP sizedst的大小
3.2.2、返回值
成功dst 失败NULL
4、sockaddr地址结构服务器server写法
4.1、struct sockaddr_in addr
Addr.sin_familyAF_INET/AF_INET6
Addr.sin_porthtons(9527)Int dst;Inet_pton(AF_INET,”192.168.22.54”,(void*)dst)
Addr.sin_addr.s_addrdst
addr.sin_addr.s_addrhtonl(INADDR_ANY)//[重点]取出系统中有效的任意IP地址二进制类型
Bind(fd,(sockaddr *)addr,size)
注意这里sockaddr给bind传参的时候需要强转
4.2、struct sockaddr_in结构体
struct sockaddr_in {sa_family_t sin_family; /* address family: AF_INET */in_port_t sin_port; /* port in network byte order */struct in_addr sin_addr; /* internet address */
};
/* Internet address.*/
struct in_addr {uint32_t s_addr;/* address in network byte order */
};5、socket模型创建流程分析
一个客户端和一个服务器通信时除了各自的一个套接字以外还有一个监听套接字一共是三个套接字
6、socket和bind
6.1、socket
6.1.1、socket函数
#includesys/socket.h
Int socket(int domin,int type,int protocol); //创建一个套接字
1DominAF_INET、AF_INET6、AF_UNIX(创建本地套接字时使用) 2TypeSOCK_STREAM(流式类型)、SOCK_DGRAM报式类型 3Protocol0前面的type有两个这里的protocol代表的是对前面两种类型的选择0代表SOCK_STREAM,代表协议是TCP1代表的是SOCK_DGRAM代表协议是UDP
6.1.2、返回值
成功新套接字所对应的文件描述符 失败-1设置errno
6.2、bind
6.2.1、bind函数
#includearpa/inet.h
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);//给socket绑定一个地址结构IPport1Sockfd:socket函数返回值 Struct sockaddr_in addr Addr.sin_familyAF_INET; Addr.sin_porthtons(8888); Addr.sin.s_addrhtonl(INADDR_ANY);//服务器写法INADDR_ANY 2Addr:(struct sockaddr *)addr Addrlen:sizeof(addr) 地址结构的大小 3返回值 成功0 失败-1 errno
7、listen和accept
7.1、listen
7.1.1函数原型
int listen(int sockfd,int backlog);//设置同时与服务器建立连接的上限数1Sockfdsocket函数返回值 2Backlog上限数值最大值是128
7.1.2、返回值
成功0 失败-1 errno
7.2、accept
7.2.1、函数原型
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);//阻塞等待客户端建立连接成功的话返回一个与客户端成功链接的socket文件描述符1Sockfdsocket函数返回值 Addr传出参数成功与服务器建立连接的那个客户端的地址结构IPport 2Socklen_t client_addr_lensizeofaddr Addrlen:传入传出。client_addr_len 入addr的大小出客户端addr实际大小
7.2.2、返回值
成功能与服务器进行数据通信的socket对应的文件描述符 失败-1errno
8、connect函数client
8.1.1、函数原型
Int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen);//使用现有的socket与服务器建立连接1Sockfdsocket函数返回值 Struct sockaddr_in server_addr;//服务器地址结构 Server_addr.sin_familyAF_INET Server_addr.sin_port8087//跟服务器bind时设定的port完全一致 Server_adde.sin_addr.s_addr Inet_pton(AF_INET,”服务器的Ip地址”server_addr.sin_addr.s_addr) 2Addr传入参数服务器的地址结构 3Addrlen:服务器的地址结构的长度
8.1.2、返回值
成功0 失败-1 如果不使用bind绑定客户端地址结构采用“隐式绑定”
二、TCP通信案例
1、TCP通信模型
1.1、需求分析
创建一个能从客户端输入10次HELLO从服务端转换成10个hello的通信器。
1.2、功能简介
该通信器可以从客户端发送10条HELLO给服务端服务端接收之后可以在屏幕上输出10个hello。
2、步骤分析与代码
2.1、server
2.1.1、步骤分析
1socket();//创建socket 2bind();//绑定服务器地址结构 3listen();//设置监听上限 4connect();//阻塞监听客户端连接 5read(fd);读socket获取客户端数据 6toupper();//数据处理 7write(fd); 8read(fd); 9close();
2.1.2、server.c代码
#includestdio.h #includestdlib.h
#includestring.h
#includeunistd.h
#includeerrno.h
#includepthread.h
#includesys/socket.h
#includectype.h
#includearpa/inet.h#define SERVER_PORT 8087void sys_err(char*str)
{perror(str);exit(1);
}int main(int argc,char*argv[])
{int lfd0,cfd0;int ret,i;char buf[BUFSIZ],client_IP[1024]; int conter10;struct sockaddr_in server_addr,client_addr;socklen_t client_addr_len;server_addr.sin_familyAF_INET;server_addr.sin_porthtons(SERVER_PORT);server_addr.sin_addr.s_addrhtonl(INADDR_ANY);lfdsocket(AF_INET,SOCK_STREAM,0);if(lfd-1){sys_err(socket error);}bind(lfd,(struct sockaddr*)server_addr,sizeof(server_addr));listen(lfd,128);client_addr_lensizeof(client_addr);cfdaccept(lfd,(struct sockaddr *)client_addr,client_addr_len);if(cfd-1){sys_err(accept error);}printf(client ip:%s port:%d\n,inet_ntop(AF_INET,client_addr.sin_addr.s_addr,client_IP,sizeof(client_IP)),ntohs(client_addr.sin_port));while(--conter){retread(cfd,buf,sizeof(buf));write(STDOUT_FILENO,buf,ret);for(i0;iret;i){buf[i]toupper(buf[i]); }write(cfd,buf,ret);}close(lfd);close(cfd);return 0;
}
2.2、client
2.2.1、步骤分析
1socket创建socket 2connect与服务器建立连接 3write 4read 5显示读取结果 6close
2.2.2、client.c代码
#includestdio.h
#includestdlib.h
#includestring.h
#includeunistd.h
#includeerrno.h
#includepthread.h
#includesys/socket.h
#includearpa/inet.h#define SERVER_PORT 8087void sys_err(char*str)
{perror(str);exit(1);
}int main(int argc,char*argv[])
{int cfd;int conter10;char buf[BUFSIZ];struct sockaddr_in server_addr;server_addr.sin_familyAF_INET;server_addr.sin_porthtons(SERVER_PORT);inet_pton(AF_INET,127.0.0.1,server_addr.sin_addr.s_addr);cfdsocket(AF_INET,SOCK_STREAM,0);if(cfd-1){sys_err(socket error);}int retconnect(cfd,(struct sockaddr *)server_addr,sizeof(server_addr));if(ret!0){sys_err(connect error);}while(--conter) {write(cfd,hello\n,6);retread(cfd,buf,sizeof(buf));write(STDOUT_FILENO,buf,ret);sleep(1);}close(cfd);return 0;
}
三、三次握手 和四次挥手
1、三次握手
1、客户端发送一个STN标志位。500(0)表示的是发送一个包号为500数据大小为0的数据包从而告知服务器我要与你建立连 2、此时服务器会回应一个ACK表示我接收到了你的请求501号包以前的数据我都收到了。服务器也会发送一个SYN标志位告诉客户端我要和你建立连接 3、客户端收到服务器的请求以后也会回应一个ACK表示请求收到了。三次连接的过程发生在内核。在用户层面的体现就是 accept (内核)和connect(用户)函数成功执行并返回了
2、数据通信三次握手之后
客户端发送数据时又发送了一个ACK701是为了确保服务器连接成功因为如果三次握手时发送的ACK回应服务器没收到就不能成功发送数据。
3、四次挥手关闭连接
四次挥手的原因是半关闭 三次握手之后成功建立连接服务器可以向客户端发送数客户端也可以向服务器发送数据。这里客户户端关闭连接之后服务器就只能发送数据不能读取读取数据了。 为什么客户端半关闭之后服务器可以向客户端发送数据?因为套接字里面有两个缓冲区一个读缓冲区和一个写缓冲区半关闭就相当于把写缓冲区关掉了客户端无法向服务器发送数据但是可以读服务器发送过来的数据。