OSI七层模型
应用层,表达层,会话层,传输层,网络层,数据链路层,物理层
(顺口溜式记忆:应用表示会话层,传输网络链路层,还有一个物理层)
TCP/IP四层模型
应用层,传输层,互联网络层,网络接口层
实现一个服务器向连接的客户端发送系统时间
服务器中止时打印出结束信息
sockfd设为全局变量
sig_handler为终止信号运行函数
int socket(int domain, int type, int protocol);
应用层:面向用户
传输层:如TCP,UDP
网络层:如IP
socket位于应用层与传输层之间
返回值:套接字描述符(一切皆文件)
domain:协议族(family)决定地址类型如:AF_INET
type:socket类型如:SOCK_STREAM,SOCK_DGRAM
protocol:指定协议如:IPPROTO_TCP、IPPTOTO_UDP
或者填0会根据type选择对应的
这个套接字用于监听
socket结构体如下:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
把地址族的特定地址给socket,不调用会随机分配端口号
返回值:成功返回0
sockfd:套接字描述符
addr:套接字协议地址
addr:地址大小
int listen(int sockfd, int backlog);
返回值:成功返回0
sockfd:套接字描述符
backlog:队列最大连接数
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值:一个新的连接客户端的描述符(区别于前面监听用的)
sockfd:监听用套接字
addr:客户端的地址信息,不需要可设为NULL
addrlen:地址长度,同样可为NULL
通过write给客户端发送服务器当前时间
右边终端:编译-运行-终止
服务器源码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int sockfd;
void sig_handler(int signo)
{
if(signo == SIGINT)
{
printf("server close\n");
close(sockfd);
exit(1);
}
}
/*输出连接的客户端的信息*/
void out_addr(struct sockaddr_in *clientaddr)
{
//网序转主机序
int port = ntohs(clientaddr->sin_port);
char ip[16];
memset(ip,0,sizeof(ip));
inet_ntop(AF_INET,
&clientaddr->sin_addr.s_addr,ip,sizeof(ip));
printf("client:%s(%d) connected\n",ip,port);
}
void do_service(int fd)
{
long t = time(0);
char *s = ctime(&t);
size_t size = strlen(s) * sizeof(char);
if(write(fd,s,size) != size)
{
perror("write error");
}
}
int main(int argc,char *argv[])
{
if(argc < 2)
{
printf("usage:%s #port\n",argv[0]);
exit(1);
}
if(signal(SIGINT,sig_handler) == SIG_ERR)
{
perror("signal sigint error");
exit(1);
}
/*创建socket
*socket为结构体
*AF_INET: IPV4
*SOCKET_STREAM:tcp协议
*/
sockfd = socket(AF_INET,SOCK_STREAM,0);
/*
* socket跟地址绑定(ip/port)
*/
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
/*填入ip,port,internet地址族*/
serveraddr.sin_family = AF_INET;//ipv4
serveraddr.sin_port = htons(atoi(argv[1]));//port
/*可以绑定指定ip
如:serveraddr.sin_addr.s_addr = "192.168.1.10";
或者用系统定义的宏
#define INADDR_ANY (uint32_t)0x00000000
可以响应所有接口的请求
*/
serveraddr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd,(struct sockaddr*)&serveraddr,
sizeof(serveraddr)) < 0)
{
perror("bind error");
exit(1);
}
/*监听指定端口
*接受来自服务器的请求
*将客户端请求放置对应队列
*/
if(listen(sockfd,10) < 0)//10为队列长度
{
perror("listen error");
exit(1);
}
/*调用accept从队列中获取一个客户端请求
*若没有链接会阻塞,直到有一个连接
*/
struct sockaddr_in clientaddr;
socklen_t clientaddr_len = sizeof(clientaddr);
while(1)
{
int fd = accept(sockfd,(struct sockaddr*)&clientaddr,
&clientaddr_len);
if(fd < 0)
{
perror("accept error");
continue;
}
/*调用系统IO通信*/
out_addr(&clientaddr);
do_service(fd);
/*关闭套接字*/
close(fd);
}
return 0;
}
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
对应于服务器listen
返回值:成功返回0失败-1
sockfd:客户端套接字描述符
addr:要连接的服务器地址
addrlen:地址长度
客户端源代码:
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[])
{
if(argc < 3)
{
printf("usage:%s ip port\n",argv[0]);
exit(1);
}
/*创建socket*/
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0)
{
perror("socket error");
exit(1);
}
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);
/*连接到服务器*/
if(connect(sockfd,(struct sockaddr*)&serveraddr,
sizeof(serveraddr)) < 0)
{
perror("connect error");
exit(1);
}
/*系统IO通信*/
char buffer[1024];
memset(buffer,0,sizeof(buffer));
size_t size;
if((size = read(sockfd,buffer,sizeof(buffer))) < 0)
{
perror("read error");
}
if(write(1,buffer,size) != size)
{
perror("write error");
}
/*关闭套接字*/
close(sockfd);
return 0;
}