Linux下简单的socket通信

来源:互联网 发布:u center软件 编辑:程序博客网 时间:2024/04/27 21:33

实现一个简单的echo服务器

代码实现

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