⽹络套接字编程:创建客户端和服务器端的流程及完整代码TCP通信创建客户端和服务器端的流程
⽹络套接字编程
套接字 socket , 也可以做进程间通信(ROS)
TCP协议通信 (传输层协议)安全可靠传输协议, 需要先建⽴链接才进⾏收发数据
优点 : 安全,协议层会校验, 缺点:实时性差, 粘包问题(数据流)
应⽤场景: 传输对数据安全⾼的数据, ⽂件, 控制指令
流程
> 服务器端
1.创建套接字
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
返回值:套接字描述符(类似⽂件描述符) ,失败返回-1
参数:int domain地址族
(AF_INET-IPV4, AF_INET6-IPV6)
int type 数据类型
⽐如:SOCK_STREAM(tcp协议) SOCK_DGRAM(udp协议) SOCK_RAW(原始套接字)
int protocol 协议
⼀般设置为0, 系统⾃动根据数据类型确定对应的协议
2. 绑定
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
返回值: 成功返回0, 失败返回-1
参数: int sockfd 套接字描述符
const struct sockaddr *addr 要绑定的端⼝, 地址
socklen_t addrlen 地址长度
结构体
struct sockaddr {
sa_family_t sa_family; //地址族 IPV4,IPV6
char sa_data[14]; //包含4字节ip地址, 2字节端⼝号 , 8字节预留
}
设计⼀个struct sockaddr替代结构体 struct sockaddr_in
struct sockaddr_in
{
short int sin_family; /地址族/
unsigned short int sin_port; /端⼝号/
struct in_addr sin_addr; /IP地址/
unsigned char sin_zero[8]; /填充0 以保持与struct sockaddr同样⼤⼩/
};
struct in_addr {
in_addr_t s_addr;
/*in_addr_t为 32位的unsigned int,该⽆符号整数采⽤⼤端字节序。 */
};
3. 监听
int listen(int sockfd, int backlog);
返回值: 成功返回0, 失败返回-1
参数: int sockfd: 套接字描述符
int backlog : 监听队列长度
4.接受链接(接受连接成功会创建⼀个新的套接字, ⽤来与客户端收发数据)
1. 如果没有客户端连接, accept函数数阻塞,
2. 当有客户端连接并且连接成功, 会返回⼀个套接字描述符 (这个套接字描述符主要使⽤来与客户端实现收发数据)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值: 成功返回套接字–与客户端收发数据使⽤, 失败返回-1
参数:struct sockaddr *addr ⽤来存储客户端地址
socklen_t *addrlen 告诉存储地址的空间长度
5.在服务器端读取客户端发送的数据
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
tcp协议通客户端
1.创建套接字
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
返回值:套接字描述符(类似⽂件描述符) ,失败返回-1
参数:int domain地址族 AF_INET-IPV4, AF_INET6-IPV6
int type 数据类型 ⽐如:SOCK_STREAM(tcp协议) SOCK_DGRAM(udp协议) SOCK_RAW(原始套接字)int protocol 协议 ⼀般设置为0, 系统⾃动根据数据类型确定对应的协议
2.连接服务器
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
返回值 连接成功返回0, 失败返回-1
参数:int sockfd 套接字描述符
const struct sockaddr *addr 要连接的服务器地址和端⼝ struct sockaddr_in
socklen_t addrlen 地址对应的长度
3. 发送数据 write, send
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
返回:成功返回发送的字节数, 失败返回-1
参数:int sockfd套接字描述符
const void *buf 要发送的数据⾸地址
size_t len发送数据对应长度
int flags 标识设置为0
以下是客户端&服务器的代码实现过程
//服务器端
/*
点对点通信
服务器端实现步骤:
socket-》创建套接字
write的返回值
bind-》绑定
listen-》监听
accept -》接收
close-》关闭
*/
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
int main(void)
{
//创建接套字
int socketfd =socket(AF_INET,SOCK_STREAM,0);//AF_INET ->IPV4 / AF_INET6->IPV6 /SOCK_STREAM(TCP协议)if(socketfd <0)
{
perror("socket fail");
return-1;
}
//初始化--绑定
struct sockaddr_in addr;
//struct sockaddr_in *p = (struct sockaddr_in*)&addr;这个和上⾯的结构体是⼀样的,只是细化了
memset(&addr,0,sizeof(addr));//清空
addr.sin_family = AF_INET;//地址族
addr.sin_port =htons(8989);//转化端⼝号
addr.sin_addr.s_addr = INADDR_ANY;//结构体⾥的结构sin_addr⾥的s_addr;INADDR_ANY这个宏就是0
//绑定->端⼝号只能绑定⼀次,被⽤过不能再⽤
int ret =bind(socketfd,(struct sockaddr *)&addr,sizeof(addr));//bind()是绑定函数
if(ret <0)
{
perror("绑定失败");
return-1;
}
ret =listen(socketfd,5);//长度为5
if(ret <0)
{
perror("监听失败");
return-1;
}
//接受连接,这个函数是阻塞的
struct sockaddr_in clientaddr;
socklen_t len =sizeof(clientaddr);
int clientfd =accept(socketfd,(struct sockaddr*)&clientaddr,&len); if(clientfd <0)
{
perror("连接失败");
return-1;
}
printf("有新的客户端\n");
//接受读取数据->读到的是http通信的数据
char recvbuffer[1024];
while(1)
{
ssize_t rd =read(clientfd, recvbuffer,1024);
if(rd <=0)
{
printf("客户端掉线\n");
break;
}
printf("读到的数据:%s\n", recvbuffer);//数据时浏览器发过来的}
//关闭
close(clientfd);
close(socketfd);
return0;
}
/*
客户端实现步骤:
socket-》创建套接字
"bind-》绑定"->可要可不要
listen-》监听
accept -》接收
close-》关闭
*/
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
int main(void)
{
//创建套接字
int socketfd =socket(AF_INET,SOCK_STREAM,0);//AF_INET ->IPV4 / AF_INET6->IPV6 /SOCK_STREAM(TCP协议)if(socketfd <0)
{
perror("socket fail");
return-1;
}
//连接服务器
struct sockaddr_in addr;
//socklen_t len = sizeof(addr);
memset(&addr,0,sizeof(addr));//清空
addr.sin_family = AF_INET;
addr.sin_port =htons(8989);
addr.sin_addr.s_addr =inet_addr("192.168.24.21");
int ret =connect(socketfd,(struct sockaddr *)&addr,sizeof(addr));//三次握⼿已经在这个connect函数内部完成了
//发送数据
//char *msg = "hello world\n";
char msg[128];
while(1)
{
printf("请输⼊要发送的数据:\n");scanf("%s", msg);//从键盘中输⼊
write(socketfd, msg,strlen(msg)+1);
}
//关闭
close(socketfd);
return0;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论