1 套接字的概念
Linux当中的一种文件类型,伪文件,不占用存储空间,可进行IO操作,可间接看做文件描述符使用。
2 通信方式有哪几种,Socket有什么区别
通信方式:信号量 管道 消息队列 共享内存 套接字
区别:套接字支持网络上两台以上的设备进行通信,其他其中只能在一台设备上
原因: Socket有双个缓冲区
原文链接:https://blog.csdn.net/weixin_44972997/article/details/115751075
本地网络字节序:
socket模型创建流程分析
转换函数 :toupper
函数:
int socket(int domain, int type, int proto‐col);
int domain :AF_UNIX AF_INET 、AF_INET6. 选用的协议
type:SOCK_STREAM SOCK_DGRAM 流(TCP)、报(UDP)
proto‐col:0
返回值:成功:新 套接字所对应的文件描述符
失败:-1;
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);给socket绑定一个地址结构(IP+端口号)
sockfd:socket返回值
struct sockadd_in addr:
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
const struct sockaddr *addr:&addr
addrlen:地址结构的大小
listen(int sockfd,int backlog)设置同时与服务器建立连接的上限数(同时进行3次握手的客户端数量)
sockfd:
backlog:上限数字
int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen) 能与服务器进行数据通信的socket
addr:传出参数 成功与服务器建立连接的哪个客户端的地址结构
int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen )用来与服务器进行链接
sockfd:
addr:传入参数 服务器的地址结构
addrlen:服务器的地址结构大小
成功:0
//服务端程序
#include <ctype.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#define SERV_PORT 9527
#define BUFSIZE 1024
int main()
{
int cfd;
int lfd = socket(AF_INET,SOCK_STREAM,0);//TCP协议
if(lfd==-1)
{
perror("socket");
exit(-1);
}
char buf[BUFSIZE];
//创建一个服务器的地址结构
struct sockaddr_in s_addr,clit_addr;//shezhi fuwuduan kehuduan
s_addr.sin_family = AF_INET;
//取值范围0~65535
s_addr.sin_port = htons(SERV_PORT);//htons:16位 htonl:32位 本地字节转网络字节htonsl
s_addr.sin_addr.s_addr = htons(INADDR_ANY);
//2、绑定自己IP和端口号
bind(lfd,(struct sockaddr*)&s_addr,sizeof(s_addr));
//3.监听
listen(lfd,128);
int clit_addr_len = sizeof(clit_addr);
//4.能与服务器进行通信的socket
cfd = accept(lfd,(struct sockaddr*)&clit_addr,&clit_addr_len);
if(cfd ==-1)
{
perror("accept");
exit(-1);
}
printf();
//5.读操作
while(1)
{
int ret = read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
for(int i= 0;i<ret;i++)
{
buf[i] = toupper(buf[i]);
//write(cfd,buf,ret);
}
}
close(lfd);
close(cfd);
return 0;//错误返回-1
}
CS模型的实现
TCP通信流程 分析:
server:服务器
-
socket()
-
bind()
-
listen()
-
accep()
-
read()读socket获取客户端数据
-
小转大 toupper()
-
write()
-
close()
client:
-
socket()
-
connect()
-
write()
-
read()
-
显示读取结果
函数原型:
//1. int socket(int domain, int type, int proto‐col); //1. int domain :AF_UNIX AF_INET 、AF_INET6. 选用的协议 //2. type:SOCK_STREAM SOCK_DGRAM 流(TCP)、报(UDP) //3. proto‐col:0 返回值:成功:套接字所对应的文件描述符 • 失败:-1; //2.给socket绑定一个地址结构(IP+端口号) int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //1. sockfd:socketfd //2. struct sockadd_in addr: addr.sin_family = AF_INET; addr.sin_port = htons(8888); //8888用于客户端连接 addr.sin_addr.s_addr = htonl(INADDR_ANY); //3 htonl() 是一个函数族中的一个成员,用于将主机字节序的 16 位整数转换为网络字节序(大端字节序)的 16 位整数。 这个函数族包括以下函数: htons():将主机字节序的 16 位整数转换为网络字节序的 16 位整数。 htonl():将主机字节序的 32 位整数转换为网络字节序的 32 位整数。 ntohs():将网络字节序的 16 位整数转换为主机字节序的 16 位整数。 ntohl():将网络字节序的 32 位整数转换为主机字节序的 32 位整数。 const struct sockaddr *addr:&addr; addrlen:地址结构的大小 //4.监听 监听上限 listen(int sockfd,int backlog)设置同时与服务器建立连接的上限数(同时进行3次握手的客户端数量) //1.监听 sockfd: //2.监听上限 backlog:上限数字 //5.阻塞连接 服务器端用于接受客户端连接 int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen) 能与服务器进行数据通信的socket addr:传出参数 成功与服务器建立连接的哪个客户端的地址结构
获取客户端地址结构:
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
参数说明如下:
-
af
:地址族(Address Family),可以是AF_INET
(IPv4)或AF_INET6
(IPv6)。 -
src
:指向存储 IP 地址的结构体的指针,可以是struct in_addr*
(IPv4)或struct in6_addr*
(IPv6)。 -
dst
:指向保存转换后的 IP 地址字符串的缓冲区。 -
size
:缓冲区的大小,确保足够存储转换后的 IP 地址。
int inet_pton(int af, const char *src, void *dst);
参数说明如下:
-
af
:地址族(Address Family),可以是AF_INET
(IPv4)或AF_INET6
(IPv6)。 -
src
:指向以字符串形式表示的 IP 地址的指针。 -
dst
:指向存储转换后 IP 地址的结构体的指针,可以是struct in_addr*
(IPv4)或struct in6_addr*
(IPv6)。
具体代码实现:
//server.c
//服务端程序
#include <ctype.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#define SERV_PORT 9527
#define BUFSIZE 1024
int main()
{
int cfd;
int lfd = socket(AF_INET,SOCK_STREAM,0);//TCP协议
if(lfd==-1)
{
perror("socket");
exit(-1);
}
char buf[BUFSIZE];
char client_IP[1024];
//创建一个服务器的地址结构
struct sockaddr_in s_addr,clit_addr,clit_IP;//shezhi fuwuduan kehuduan
s_addr.sin_family = AF_INET;
//取值范围0~65535
s_addr.sin_port = htons(SERV_PORT);//htons:16位 htonl:32位 本地字节转网络字节htonsl
s_addr.sin_addr.s_addr = htons(INADDR_ANY);
//2、绑定自己IP和端口号
bind(lfd,(struct sockaddr*)&s_addr,sizeof(s_addr));
//3.监听
listen(lfd,128);
int clit_addr_len = sizeof(clit_addr);
//4.能与服务器进行通信的socket
cfd = accept(lfd,(struct sockaddr*)&clit_addr,&clit_addr_len);
if(cfd ==-1)
{
perror("accept");
exit(-1);
}
printf("client ip:%s\n",inet_ntop(AF_INET,&(clit_addr.sin_addr),client_IP,sizeof(client_IP)));
printf("client port:%d\n",ntohs(clit_addr.sin_port));
//5.读操作
while(1)
{
int ret = read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
for(int i= 0;i<ret;i++)
{
buf[i] = toupper(buf[i]);
//write(cfd,buf,ret);
}
}
close(lfd);
close(cfd);
return 0;//错误返回-1
}
//客户端
// date: 2023年07月15日 星期六 10时46分10秒
/// player: wenrou
/// // path: /mnt/hgfs/LuinxFile/GEC_2301/06_网络编程/01_Socket编程/client.c /
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define SERV_PORT 9527
int main()
{
char buf[BUFSIZ];
int cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd == -1)
{
perror("client socket");
}
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr.s_addr);
//serv_addr.sin_addr.s_addr = htons(INADDR_ANY)//INADDR_ANY
//int ret = connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
int ret = connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(ret==-1)
{
perror("connect");
}
int cout = 10;
while(--cout)
{
write(cfd,"hello",5);
ret = read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
}
close(cfd);
return 0;
}