TCP服务器的模型
1>建立socket连接(产生socket套接字)
socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:
建立socket连接
参数:
domain:协议
AF_UNIX, AF_LOCAL Local communication unix(7) 地址族
本地连接协议 域通信
AF_INET IPv4 Internet protocols ip(7)
IPv4协议
AF_INET6 IPv6 Internet protocols ipv6(7)
IPv6协议
type:类型
SOCK_STREAM:流式套接字 (TCP)
SOCK_DGRAM:数据报文套接字 (UDP)
SOCK_RAW:原始套接字
protocol:0,前面的配置可用
返回值:
成功返回套接字文件描述符
失败返回-1,并返回错误码
2>绑定IP和端口号
bind
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:
绑定IP和端口号
参数:
sockfd:socket返回的文件描述符
addr:sockaddr *addr
addrlen:addr的长度
返回值:
成功返回0
失败返回-1,并返回错误码
struct sockaddr { //弃用
sa_family_t sa_family; // unsigned short
char sa_data[14];
}---16个字节
sockaddr_in(在netinet/in.h中定义):
struct sockaddr_in {
short int sin_family; /* Address family */地址族
unsigned short int sin_port; /* Port number */ 端口号
struct in_addr sin_addr; /* Internet address */IP地址
unsigned char sin_zero[8]; /* Same size as struct sockaddr */ 充数用的
};
端序:
大端序:低位数据保存在高位地址上,高位数据保存在低位地址上
小端序:高位数据保存在高位地址上,低位数据保存在低位地址上
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); _be16:大端序16位
_le32:小端序32位
uint16_t htons(uint16_t hostshort);
以上是把本地字节序转换为网络字节序
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
把网络字节序转换为本地字节序
IP地址转换:本地地址转换成网络地址
第一种:
inet_aton
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
功能:
本地地址转换成网络地址
参数:
cp:字符串IP的地址:192.168.50.XX
inp:转换后的数据保存的地址
返回值:
如果转换有效。返回非0
如果转换无效。返回0
第二种转换:
inet_addr
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
功能:
本地地址 变 网络地址
参数:
cp:字符串IP地址:192.168.50.xx
返回值:
如果转换有效,返回网络二进制数据
如果转换无效,返回INADDR_NONE
第三种:
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
功能:
将字符串src转换为af地址族的一个网络二进制地址
参数:
af :地址族:AF_INET AF_INET6
src:IP地址:192.168.50.xx
dst:转换后的网络地址
返回值:
成功返回0
如果af不匹配返回-1
3>监听
listen
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:
监听,将主动连接变成被动连接
参数:
sockfd:socket返回的文件描述符
backlog:同一瞬间允许同时连接的客户端数量
返回值:
成功返回0
失败返回-1,并返回错误码
4>等待客户端连接
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
阻塞等待客户端连接
参数:
sockfd:socket返回的文件描述符
addr:struct sockaddr * -->用来保存客户端的IP和端口
addrlen:addr的长度
返回值:
成功返回非负的文件描述符
失败返回-1,并返回错误码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <strings.h>
int main(void)
{
//创建socetk套接字
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
exit(-1);
}
//绑定IP和端口号
struct sockaddr_in server;
server.sin_family=AF_INET; //使用IPv4协议
server.sin_port=htons(12345); //端口号设定为12345
//inet_aton("192.168.50.3",&server.sin_addr); //第一种转换
//server.sin_addr.s_addr=inet_addr("192.168.50.3");//第二种转换
//inet_pton(AF_INET,"192.168.50.3",&server.sin_addr);//第三种转换
server.sin_addr.s_addr=INADDR_ANY; //第四种
if(bind(sockfd,(struct sockaddr *)&server,sizeof(server))){
perror("bind error");
exit(-1);
}
//监听
if(listen(sockfd,8)){
perror("listen error");
exit(-1);
}
//等待客户端连接
struct sockaddr_in client;
int len=sizeof(client);
int fd=accept(sockfd,(struct sockaddr *)&client,&len);
if(fd<0){
perror("accept error");
exit(-1);
}
printf("客户:%d\n",fd);
int ret;
char buf[50];
while(1){
bzero(buf,sizeof(buf));
ret=recv(fd,buf,sizeof(buf),0);
if(ret>0){
printf("%s\n",buf);
}
}
return 0;
}
2>客户端的模型
TCP客户端的模型
1>建立socket连接(产生socket套接字) //买手机
2>写入IP和端口号 //绑电话卡
3>连接 //拨电话
4>发送recv
线程:
5>接收send
1>建立socket连接
2>写入IP和端口号
写入结构体,不需要写bind
3>连接
connect
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:
连接服务器
参数:
sockfd:socket返回的文件描述符
sockaddr *addr:保存服务器的IP和端口号
addrlen:addr的长度
返回值:
成功返回0
失败返回-1,并返回错误码
4>发送/接收
1>发送
send
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
发送数据
参数:
sockfd:socket返回的文件描述符
buf:数据存放的地方
len:buf的长度
flags: 0
返回值:
成功返回发送的字节数
失败返回-1,并返回错误码
2>接收
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
接收数据
参数:
sockfd:socket返回的文件描述符
buf:数据存放的地方
len:buf的长度
flags: 0
返回值:
成功返回接收到的字节数
如果断开连接,则返回0
失败返回-1,并返回错误码
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
//创建socetk套接字
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket error");
exit(-1);
}
//写入服务器的IP和端口号
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(12345);
server.sin_addr.s_addr=inet_addr("192.168.50.3");
//客户的一般不写bind,写bind容易出现IP地址错误
//连接服务器
if(connect(sockfd,(struct sockaddr *)&server,sizeof(server))){
perror("connect errro");
exit(-1);
}
char buf[50];
while(1){
bzero(buf,sizeof(buf));
scanf("%s",buf);
send(sockfd,buf,strlen(buf),0);
}
return 0;
}