day8 socket编程CS模型完善错误处理

client.c

/*************************************************************************
    > File Name: client.c
    > Author: sunxingying
    > Mail: 1159015605@qq.com 
    > Created Time: 2017年06月24日 星期三 05时43分20秒
 ************************************************************************/
#include<string.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include"wrap.h"
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include"wrap.h"
#include<sys/socket.h>
#include<arpa/inet.h>

static void usage(const char *proc)
{
    printf("usage:%s[local_ip],[local_port]\n",proc);
    exit(1);
}
int main(int argc,char *argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
    }
    int cfd;
    char buf[1024];
    //声明socket结构体
    struct sockaddr_in serv_addr;
    //声明地址大小
    socklen_t serv_addr_len;
    //返回一个socket文件描述符
    //创建一个socket指定IPV4 TCP
    cfd=Socket(AF_INET,SOCK_STREAM,0);
    int n;
    //初始化一个地址结构
    //bzero(&serv_addr,sizeof(serv_addr));
    memset(&serv_addr,0,sizeof(serv_addr));
    //对结构提进行初始化
    serv_addr.sin_family=AF_INET;
    //指定端口 本地转网络字节序
    serv_addr.sin_port=htons(atoi(argv[2]));
    //指定IP 字符串类型转换为网络字节序 参3:传出参数
    inet_pton(AF_INET,argv[1],&serv_addr.sin_addr.s_addr);
    //根据地址结构链接指定服务器进程
    Connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
    while(1)
    {   
         /*从标准输入获取数据*/
        fgets(buf,sizeof(buf),stdin);
        /*将数据写给服务器*/
        Write(cfd,buf,strlen(buf));
        /*从服务器读回转换后数据*/
        n=read(cfd,buf,sizeof(buf));
         /*写至标准输出*/
        write(STDOUT_FILENO,buf,n);
    }
    //关闭链接
    Close(cfd);
    return 0;
}

server.c

/*************************************************************************
    > File Name: server.c
    > Author: sunxingying
    > Mail: 1159015605@qq.com 
    > Created Time: 2017年06月24日 星期一 06时17分16秒
 ************************************************************************/
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
//tcp_server 127.0.0.1 8080
static void usage(const char *proc)
{
    printf("usage: %s[local_ip],[local_port]\n",proc);
}
int startup(const char *_ip,int _port)
{
    int sock=socket(AF_INET,SOCK_STREAM,0);

    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_port=htons(_port);
    local.sin_addr.s_addr=inet_addr(_ip);
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        perror("bind");
        exit(2);
    }
    if(listen(sock,10)<0)
    {
        perror("listen");
        exit(4);
    }
    return sock;
}
int main(int argc,char *argv[])
{
    if(argc!=3)
    {
        usage(argv[0]);
        return 1;

    }
    int listen_sock=startup(argv[1],atoi(argv[2]));
    while(1)
    {
        struct sockaddr_in client;
        socklen_t len=sizeof(client);
        int new_sock=accept(listen_sock,\
                (struct sockaddr *)&client ,&len);
        if(new_sock<0)
        {
            perror("accept");
            continue;
        }
        printf("get a new client,%s:%d\n",\
                inet_ntoa(client.sin_addr),ntohs(client.sin_port));
        while(1)
        {
            char buf[1024];
            size_t s=read(new_sock,buf,sizeof(buf));
            if(s>0)
            {
                int i;
                 write(STDOUT_FILENO,buf,s);
                 //处理客户端数据
                 for(i=0;i<s;i++)
                 {
                     buf[i]=toupper(buf[i]);
                 }                             
                 //处理完数据回写给客户端 
                 write(new_sock,buf,s);

            }
        }
    }
    close(listen_sock);
    return 0;

}

wrap.h

#ifndef __WRAP_H_
#define __WRAP_H_

void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);

#endif

wrap.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>

void perr_exit(const char *s)
{
    perror(s);
    exit(-1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int n;

again:
    //accept是慢速系统调用,有可能在阻塞期间被信号中断
    //被信号中断时errno 被设置为ECONNABORTED或者EINTR
    if ((n = accept(fd, sa, salenptr)) < 0) {
        if ((errno == ECONNABORTED) || (errno == EINTR))
            goto again;
        else
            perr_exit("accept error");
    }
    return n;
}

int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

    if ((n = bind(fd, sa, salen)) < 0)
        perr_exit("bind error");

    return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

    if ((n = connect(fd, sa, salen)) < 0)
        perr_exit("connect error");

    return n;
}

int Listen(int fd, int backlog)
{
    int n;

    if ((n = listen(fd, backlog)) < 0)
        perr_exit("listen error");

    return n;
}

int Socket(int family, int type, int protocol)
{
    int n;

    if ((n = socket(family, type, protocol)) < 0)
        perr_exit("socket error");

    return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
    ssize_t n;
//read也是慢速系统调用
//read返回值:
/*
 *  1. >0实际读到的字节数 buf=1024 1.==buf 1024 2. <buf 56
 *  2. ==0读到了(文件、管道、socket末尾了--对端关闭
 *  3. -1 异常
 *          1. errno==EINTR 被信号中断  重启/quit
 *          2. error==EAGAIN(EWOULDBLOCK)非阻塞方式读,并且没有数据
 *          3. 其他值 出现错误 --perror exit
 *
 */
again:
    if ( (n = read(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
    ssize_t n;
//write也是慢速系统调用也会遇到同上问题,
again:
    if ( (n = write(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

int Close(int fd)
{
    int n;
    if ((n = close(fd)) == -1)
        perr_exit("close error");

    return n;
}

/*参三: 应该读取的字节数*/
ssize_t Readn(int fd, void *vptr, size_t n)
{
    size_t  nleft;              //usigned int 剩余未读取的字节数
    ssize_t nread;              //int 实际读到的字节数
    char   *ptr;

    ptr = vptr;
    nleft = n;
    /*
     *假设socket有4096字节,而以太网帧格式最大一次是1500
     *一个数据包就发不完了,readn(cfd,buf,4096);
     *nleft是剩余还未读的字节数,nleft=4096-1500,
     *读完指针向后偏移
     */
    while (nleft > 0) {
        if ((nread = read(fd, ptr, nleft)) < 0) {
            if (errno == EINTR)
                nread = 0;
            else
                return -1;
        } else if (nread == 0)
            break;

        nleft -= nread;
        ptr += nread;
    }
    return n - nleft;
}
/*writen同readn*/
ssize_t Writen(int fd, const void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char *ptr;

    ptr = vptr;
    nleft = n;
    while (nleft > 0) {
        if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
            if (nwritten < 0 && errno == EINTR)
                nwritten = 0;
            else
                return -1;
        }

        nleft -= nwritten;
        ptr += nwritten;
    }
    return n;
}

static ssize_t my_read(int fd, char *ptr)
{
    static int read_cnt;
    static char *read_ptr;
    static char read_buf[100];

    if (read_cnt <= 0) {
again:
        if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
            if (errno == EINTR)
                goto again;
            return -1;
        } else if (read_cnt == 0)
            return 0;
        read_ptr = read_buf;
    }
    read_cnt--;
    *ptr = *read_ptr++;

    return 1;
}
/*readline ---fgets*/
//传出参数vptr
ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n, rc;
    char    c, *ptr;
    ptr = vptr;
    for (n = 1; n < maxlen; n++) {
        if ( (rc = my_read(fd, &c)) == 1) {
            *ptr++ = c;
            if (c  == '\n')
                break;
        } else if (rc == 0) {
            *ptr = 0;
            return n - 1;
        } else
            return -1;
    }
    *ptr  = 0;

    return n;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值