网络套接字编程
套接字 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, 系统自动根据数据类型确定对应的协议
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,该无符号整数采用大端字节序。 */
};
int listen(int sockfd, int backlog);
返回值: 成功返回0, 失败返回-1
参数: int sockfd: 套接字描述符
int backlog : 监听队列长度
4.接受链接(接受连接成功会创建一个新的套接字, 用来与客户端收发数据)
- 如果没有客户端连接, accept函数数阻塞,
- 当有客户端连接并且连接成功, 会返回一个套接字描述符 (这个套接字描述符主要使用来与客户端实现收发数据)
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 地址对应的长度
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-》创建套接字
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);//长度为5if(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("读到的数据:%sn", recvbuffer);//数据时浏览器发过来的}//关闭close(clientfd);close(socketfd);return 0;}
//客户端
/*
客户端实现步骤:
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 worldn";char msg[128];while(1){printf("请输入要发送的数据:n"); scanf("%s", msg); //从键盘中输入write(socketfd, msg, strlen(msg)+1);}//关闭close(socketfd);return 0;
}
本文发布于:2024-01-29 00:09:48,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170645819311301.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |