Linux下简单的socket通信

实现一个简单的echo服务器

代码实现

/**
 * @file server.c
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXLINE     1024
#define SERVERADDR  "127.0.0.1"
#define SERVERPORT  8000
#define QUEUE       20

int init(int type,const struct sockaddr *addr,socklen_t alen,int queuelen)
{
    int fd;
    int err = 0;

    if((fd = socket(addr->sa_family,type,0)) < 0) {
        return -1;
    }
    if(bind(fd,addr,alen) < 0) {
        goto errout;
    }
    if(type == SOCK_STREAM || type == SOCK_SEQPACKET) {
        if(listen(fd,queuelen) < 0) {
            goto errout;
        }
    }

    return fd;

errout:
    err = errno;
    close(fd);
    errno = err;
    return (-1);

}

int main(int argc, char *argv[])
{
    char ipStr[MAXLINE] = {0};
    char buf[MAXLINE] = {0};
    int i;
    int len = 0;

    int lfd,cfd;
    struct sockaddr_in server_addr,client_addr;
    socklen_t addrlen = sizeof(struct sockaddr_in);


    bzero(&server_addr,sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    inet_pton(AF_INET,SERVERADDR,&server_addr.sin_addr.s_addr);
    server_addr.sin_port = htons(SERVER_PORT);

    init(SOCK_STREAM,(struct sockaddr *)&server_addr,addrlen,QUEUELEN);

    bzero(&client_addr,sizeof(struct sockaddr_in));

    printf("Accept...\n");
    cfd = accept(lfd,(struct sockaddr *)&client_addr,&addrlen);
    if (cfd == -1) {
        perror("accept err");
        exit(1);
    }
    printf("clientaddr ip = %s\tport = %d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ipStr,sizeof(ipStr)),ntohs(client_addr.sin_port));


    len = read(cfd, buf, sizeof(buf));

    for (i = 0; i < len; i++)
        buf[i] = toupper(buf[i]);

    write(cfd, buf, len);

    close(cfd);
    close(lfd);

    return 0;

}
/**
 * @file client.c
 */
#include 
#include 
#include 

#include 
#include 

#define MAXSLEEP 128
#define MAXLINE 80
#define SERV_PORT 8000

//客户端的重新链接
int connect_retry(int sockfd,const struct sockaddr *addr,socklen_t alen)
{
    //Linux上可行
    int numsec;

    //实现指数补偿,当numsec大于允许重新连接的时间的时候,就不再连接
    for(numsec = 1; numsec <= MAXSLEEP;numsec <<= 1) {
        if(connect(sockfd,addr,alen) == 0) {
            return 0;
        }

        if(numsec <= MAXSLEEP/2) {
            sleep(numsec);
        }
    }
    return -1;
}

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, n;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    if(connect_retry(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr))) {
        perror("connect error");
        exit(1);
    }

    while (fgets(buf, MAXLINE, stdin) != NULL) {
        write(sockfd, buf, strlen(buf));
        n = read(sockfd, buf, MAXLINE);
        if (n == 0) {
            printf("the other side has been closed.\n");
            break;
        }
        else
            write(STDOUT_FILENO, buf, n);
    }

    close(sockfd);
    return 0;
}

简单函数的功能以及函数的原形

#include  
int socket(int family, int type, int protocol);

family:协议簇

family 说明
AF_INET IPv4协议
AF_INET6 IPv6
AF_LOCAL Unix域协议
AF_ROUTE 路由套接字
AF_KEY 密钥套接字

type:套接字的类型

type 说明
SOCK_STREAM(常用) 字节流套接字
SOCK_DGRAM 数据报套接字
SOCK_SEQPACKET 有序分组套接字
SOCK_RAW 原始套接字

protocol:协议类型的常量或设置为0,以选择给定的family和type组合的系统默认值

protocol 说明
IPPROTO_TCP TCP传输协议
IPPROTO_UDP UDP传输协议
IPPROTO_SCTP SCTP传输协议
#include
int inet_pton(int family,const char *strptr,void *addrptr);//成功返回1,格式不对返回0,出错返回-1
//作用:p代表表达式 n代表数值  以后所写的所有代码中都有可能会需要这个函数,所以这个函数很重要
//将char所指向的字符串,通过addrptr指针存放
//他的反函数:  inet_ntop()作用相反。可以百度查阅这个函数的功能。因为例子里我们没有涉及到,就不介绍了。以后用到的时候再说
//需要注意的是:当他发生错误的时候,errno的值会被置为EAFNOSUPPORT 关于errno值我们一会儿介绍。
#include  
int connect(int sockfd,const struct sockaddr* servaddr,socklen_t addrlen);//用connect函数来建立与TCP服务器的连接
#include
int close(int sockfd);//关闭socket,并终止TCP连接
#include 
int bind(int sockfd,const struct* myaddr,socklen_t addrlen);//把本地协议地址赋予一个套接字。也就是将32位的IPv4或128位ipv6与16位的TCP或者UDP组合。
#include
int listen(int sockfd,int backlog)//成功返回0,失败返回-1     listen函数仅由TCP服务器调用
//listen函数将会做两件事:
//1:我们在创建套接字的时候使用了socket函数,它创建的套接字是主动套接字,bind函数的功能就是通过这个将主动套接字,变成被动套接字,告诉内核应该接受指向这个套接字的请//求,CLOSED状态变成LISTEN状态
//2:本函数的第二个参数规定了内核要为该套接字排队的最大连接个数。
#include 
int accept(int sockfd,struct sockaddr* cliaddr,socklen_t *addrlen);//成功返回描述符,失败返回-1
//1、如果第二三个参数为空,代表了,我们对客户的身份不感兴趣,因此置为NULL;
//2、第一个参数为socket创建的监听套接字,返回的是已连接套接字,两个套接字是有区别的,而且非常重要。区别:我们所创建的监听套接字一般服务器只创建一个,并且一直存在。而内核会为每一个服务器进程的客户连接建立一个连接套接字,当服务器完成对某个给定客户的服务时,连接套接字就会被关闭。

你可能感兴趣的:(网络编程,socket)