linux下实现服务器与客户端(连接时给客户端发送时间)

来源:互联网 发布:昆仑虚麒麟臂升阶数据 编辑:程序博客网 时间:2024/05/19 11:50

OSI七层模型
应用层,表达层,会话层,传输层,网络层,数据链路层,物理层
(顺口溜式记忆:应用表示会话层,传输网络链路层,还有一个物理层)
TCP/IP四层模型
应用层,传输层,互联网络层,网络接口层

实现一个服务器向连接的客户端发送系统时间

从命令行接受端口号

服务器中止时打印出结束信息
这里写图片描述
sockfd设为全局变量
sig_handler为终止信号运行函数
这里写图片描述

创建socket

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结构体如下:
这里写图片描述

绑定socket结构体bind

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
把地址族的特定地址给socket,不调用会随机分配端口号
返回值:成功返回0
sockfd:套接字描述符
addr:套接字协议地址
addr:地址大小
这里写图片描述

监听listen

int listen(int sockfd, int backlog);
返回值:成功返回0
sockfd:套接字描述符
backlog:队列最大连接数
这里写图片描述

接受客户端请求accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值:一个新的连接客户端的描述符(区别于前面监听用的)
sockfd:监听用套接字
addr:客户端的地址信息,不需要可设为NULL
addrlen:地址长度,同样可为NULL
这里写图片描述

调用系统IO通信

通过write给客户端发送服务器当前时间
这里写图片描述
右边终端:编译-运行-终止
这里写图片描述
服务器源码:

#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <signal.h>#include <time.h>#include <sys/socket.h>#include <errno.h>#include <netdb.h>#include <unistd.h>#include <string.h>#include <pthread.h>#include <arpa/inet.h>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;}

实现客户端

从命令行接受ip和端口号 创建套接字

这里写图片描述

连接服务器connect

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
对应于服务器listen
返回值:成功返回0失败-1
sockfd:客户端套接字描述符
addr:要连接的服务器地址
addrlen:地址长度
这里写图片描述

调用系统IO通信

read读取来自服务器的消息
这里写图片描述

客户端源代码:

#include <stdio.h>#include <stdlib.h>#include <netdb.h>#include <string.h>#include <memory.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>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;}

编译运行服务器和客户端结果(左边服务器):

这里写图片描述
(服务器循环,每连接一个客户端就发送系统时间)

0 0
原创粉丝点击