socket TCP/UDP 基本认识和I/O多路并发服务器思路

  1. 创建一个socket , 使用socket()
    int socket(int domain, int type, int protocol);
    功能: 创建一个socket 文件
    参数:
    domain :这个socket 是用网络通信还是做进程间通信
    AF_UNIX, AF_LOCAL Local communication 进程间通信
    AF_INET IPv4 Internet protocols
    AF_INET6 IPv6 Internet protocols

type :
SOCK_STREAM : 使用tcp协议的socket
SOCK_DGRAM : 使用udp协议的socket
SOCK_RAW : 没有协议的socket , Provides raw network protocol access.
protocol :通信方式 , 默认为0

返回值:
On success, a file descriptor for the new socket is returned.
On error, -1 is returned, and errno is set appropriately.

  1. 给socket 一个固定的ip和端口
    做服务器必须要一个固定的ip 还要有一个固定的端口
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    功能:给socket 一个名字
    参数: 要操作socket
    addr: 要给名字的地址结构体指针
    struct sockaddr {
    sa_family_t sa_family; // 地址协议, 用于网络还是本地通信
    char sa_data[14]; // 地址信息, 这个是通用形式,
    }

对于网络通信需要使用另外一个结构体描述:
struct sockaddr_in {
__kernel_sa_family_t sin_family; /* Address family / 2字节
__be16 sin_port; /
Port number / 2字节
struct in_addr sin_addr; /
Internet address */ 4字节
char sin_zero[8]; // 8 bytes unused,作为填充
};

IPv4地址结构
// internet address
struct in_addr
{
in_addr_t s_addr; // u32 network address
};

addrlen : 地址结构的大小

返回值:
On success, zero is returned.
On error, -1 is returned, and errno is set appropriately.

  1. inet_addr 把一个点分十进制的ip(“192.168.1.10”)转换成网络ip地址(32位无符号的地址)
    in_addr_t inet_addr(const char *cp);
    参数:
    cp : 字符串类型的ip地址 “192.168.1.19”

返回值:
错误: -1
成功过: 转换后的ip

  1. listen 改变socket的属性, 让这个socket变成服务器socket , 处于监听状态
    int listen(int sockfd, int backlog);

sockfd:监听连接的套接字
backlog
指定了正在等待连接的最大队列长度,它的作用在于处理可能同时出现的几个连接请求。
DoS(拒绝服务)攻击即利用了这个原理,非法的连接占用了全部的连接数,造成正常的连接请求被拒绝。

返回值: 0 或 -1

  1. 查看建立的socket 信息
    netstat -nat

  2. accept 接收客户端的请求
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    参数:
    sockfd : 要操作的socket
    addr : 保存对方的地址(对方的ip和对方端口)
    addrlen : 对方地址的大小

返回值 : 
On success, these system calls return a nonnegative integer that is a descriptor for the accepted socket.
成功连接后, 会新创建一个socket 和客户端进行一对一的通信 ,返回值就是问价描述符

On error, -1 is returned, and errno is set appropriately.

  1. telnet 192.168.1.57 8000
    测试服务器连接

  2. tcp 服务器创建流程
    socket()
    bind()
    listen()
    while(1)
    {
    newsockfd = accept()
    printf()
    close(newsockfd);
    }

tcp 客户端创建流程
socket()
connect(); // 连接服务器
close(sockfd)

  1. 连接服务器 connect
    int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
    功能:发起一次连接
    参数:
    sockfd :要操作的socket
    addr :发链接的服务器地址 
    addrlen : 地址的大小
    返回值:
    成功: 0
    失败: -1

  2. 字节序
    0x11223344
    31—28 27—24 23----20 19—16 15—12 11—8 7----4 3----0
    高地址 | | | 地地址

小端: 低地址存低字节
11 22 33 44

大端: 低地址存高字节
44 33 22 11

根据应用分为:
主机字节序 :
intel : 小端
poerpc: 大端
网络字节序 : 大端

主机字节序转网络字节序:
uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

网络转主机:
uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

tcp 文件服务器

  1. list

  2. get filename

  3. put filename

  4. quit

  5. sendto 发送数据, 主要应用于udp通信中

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
参数:
sockfd :要发送数据socket
buf : 数据保存的内存地址
len :发送数据的长度
flags :发送方式, 一般为0

dest_addr : 要发送数据的地址, 这个地址sockaddr_in 类型的地址

addrlen : 地址的长度

On success, these calls return the number of characters sent.
On error, -1 is returned, and errno is set appropriately.

  1. recvfrom 接收数据, 主要应用于udp通信中
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
    struct sockaddr *src_addr, socklen_t *addrlen);
    参数: 要读数据的socket
    buf : 数据存放的内存地址
    len :要读多少个字节的数据
    flags :发送方式, 一般为0
    src_addr : 发送方的地址
    addrlen : 发送方的地址长度
    返回值:
    These calls return the number of bytes received,
    -1 if an error occurred.

思路: udp服务器实现
server.c
socket(AF_INET,SOCK_DGRAM,0);
bind()
while(1)
{
recvfrom(buf);
printf("%s",buf)
strcpy(buf,“服务器已经收到,拜拜”);
sendto(buf);
}

client.c
socket(AF_INET,SOCK_DGRAM,0);
while(1)
{
printf(">:")
fgets(buf);
sendto(buf);
recvfrom(buf);
printf(buf);

}

IO多路复用

  1. select 或poll
    int select(int nfds, fd_set *readfds, fd_set *writefds,
    fd_set *exceptfds, struct timeval *timeout);
    功能: 可以同时对多个IO进行监控(时候可读是否可写)
    参数:
    nfds: 一共要监控的文件个数 ,最大的文件描述符
    readfds :可读监控表
    writefds: 可写的监控表
    exceptfds : 其他的监控表
    timeout :超时时间
    NULL:表示使用阻塞机制, 检查完后,不满足会阻塞
    不为NULL, 为具体的超时时间
    返回值:
    成功: 可以操作io的个数
    失败:错误 -1

void FD_CLR(int fd, fd_set *set); 把一个文件从表中清除
int FD_ISSET(int fd, fd_set *set); 判断一个文件时候准备就绪, 成功为真, 失败为假
void FD_SET(int fd, fd_set *set); 把一个文件加入表中
void FD_ZERO(fd_set *set); 初始化一个表

思路: 同时监控 accept 和fgets(stdin)

并发服务器:
tcp 并发 :
socket()
bind()
listen()
while(1)
{
newsockfd = accept()
if(fork() == 0 )
{
while(1)
{

		read(); 
		printf(); 
		write(); 	
	}
	exit(0);
	
}
close(newsockfd);

}

select 并发
I/O多路复用并发服务器

DNS: 是把www.xxx.com 这个域名给转成成ip , 这个转换需要dns服务器,这个服务器实现的功能就是dns
常用的dns服务器有: 114.114.114.114
google : 8.8.8.8

gethostbyname() 根据主机名取得主机信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值