socket基础
一、套接字概述
在通信过程中,套接字使用时一定是成对出现的。
套接字只要一个问价描述符,因为其有两个缓冲区,一个缓冲区用来读,另一个缓冲区用来写
二、网络字节序
小端法:高位存高地址,低位存低地址 int a = 0x12345678
大端法:高位存低地址,低位存高地址 TCP协议规定,网络字节序必须用大端字节序,因此必须进行网络字节须和主机字节序的转化。
常见函数
#include<arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
//h表示host n表示net 本地转网络
//32位 192.168.1.110
uint16_t htons(uint16_t hostshort);
//16位针对端口
uint32_t ntohl(uint32_t netlong);
uint16_st ntohs(uint16_t netshort);
三、IP地址转换函数
#include<qrpa/inet.h>
int inet_pton(int af,const char*src,void *dst);
//inet pton点分十进制转网络字节序
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
//ntop网络字节序转点分十进制
四、网络套接字函数
4.1 socket addr 数据结构
sockaddr地址结构:
struct sockaddr_in addr;
bind(fd,(struct sockaddr *)&addr,size)
struct sockaddr_in{
sa_family_t sin_family;//AF_INET(IPV4) AF_INET6(IPV6)
in_port_t sin_port;//网络端口 htons(9527)
struct in_addr sin_addr;//intenet 地址
//int dst
//inet_pton(AF_INET,"192.157.22.45",(void *)&dst);
//addr.sin_addr.addr = dst;
/*注意
addr.sin_addr.addr = htonl(INADDR_ANY)
INADDR_ANY是一个宏,会自动提取出有效地址
*/
}
struct in_addr
{
uint32_t a_addr;//
}
4.2 socket模型创建流程
一个C/S中有三个套接字
4.3 socket和bind函数
#include<sys/socket.h>
#include<arpa/inet.ht,clit >
int socket(int domain, int type, int protocol);
/*
domain AF_INET AF_INET6 AF_UNIX
type SOCK_STREAM、SOCK_DGRAM 流式协议,倒式协议
protocol: 0 协议中的代表协议 传0就是根据type来自动选择协议,比如流式协议TCP,倒式协议UDP
返回值:成功 新套接字所对应的文件描述符
失败 -1 ERROR
*/
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//给socket绑定Ip+port 即地址结构
/*
sockfd socket函数返回值
addr (struct sockaddr *)&addr 因为有const,所以必定只能作为传入参数使用
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.a_addr = htonl(INADR_ANY);
成功返回1,失败返回-1
*/
4.4 listen和accept函数
int listen(int sockfd, int backlog); //设置同时与服务器建立连接的上限数 sockfd为文件描述符
//backlog为上限,其最大值为128
//返回值 成功0 失败 -1
int accept(int sockfd, struct *addr, socklen_t *addrlen);
//阻塞等待客户端建立连接,成功的话返回与客户端成功建立连接的套接字的文件描述符
/*
sockfd: socket函数建立的标识符
addr: 传出参数,成功与服务器建立连接的那个客户端的地址结构(Ip+port)
addrlen: 传入传出,传进去是一个数,传出时有时一个数
进的时候就是入,指的是addr的大小
出是客户端addr的实际大小
socklen_t clit_addr_len = sizeof(addr)
addrlen: &clit_addr_len
返回值: 成功返回一个和socket生产的文件描述字,其可以与服务器进行数据通信
失败返回error
*/
4.5 connect函数
int connect(int sockfd,const struct sockaddr *addr, socklen_t *addrlen )
/*
sockfd: socket函数返回值
addr:传入参数,服务器的地址结构
addrlen:服务器地址的大小
为隐式绑定
*/
五、C/S模型的TCP通信分析
server:
socket() | 创建socket() |
---|---|
bind() | 绑定服务器结构 |
listen() | 设置监听上限 |
accept() | 阻塞监听客户端连接 |
read() | 从accept()返回的socket来得到客户端的数据 |
小写转大写 | toupper() |
write(fd) | 往文件中写 |
close() | 关闭 |
client:
socket() | 创建socket() |
---|---|
connect() | 与服务器建立连接 |
write() | 写数据到socket() |
read() | 读转换后的数据 |
显示读取结果 | |
close() |
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define SERV_PORT 8888
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int lfd = 0;
char buf[1024];
lfd = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in serv_addr,clit_addr;
socklen_t clit_addr_len;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
int ret = bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
listen(lfd,128);
clit_addr_len = sizeof(clit_addr);
int cfd = accept(lfd,(struct sockaddr *)&clit_addr,&clit_addr_len);
if(cfd == -1)
sys_err("accept error");
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;
}
client.c
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#define SERV_PORT 9527
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main()
{
char buf[1024];
int cfd;
int count = 6;
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);
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd == -1)
sys_err("socket error\n");
int ret = connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
if(ret != 0)
sys_err("conect error");
while(--count)
{
write(cfd, "hello\n", 6);
ret = read(cfd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, ret);
sleep(1);
}
close(cfd);
return 0;
}