基本TCP套接字编程

来源:互联网 发布:windows抄袭mac os 编辑:程序博客网 时间:2024/05/08 02:36

建立TCO连接就好比一个电话系统。
socket函数等同于有电话可用;
listen函数是打开电话振铃;
connect函数要求我们知道对方的电话号码并拨打他;
accept函数发生在被呼叫的人应答电话之时,由accept返回客户的标识。

socket函数

    #include <sys/socket.h>    int socket(int family, int type, int protocol);

connect函数

    #include <sys/socket.h>    int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

如果调用connnect前没有调用bind函数,内核会确定源IP地址,并选择一个临时端口。
对于TCP套接字,调用connect函数会激发TCP三路握手过程,出错返回可能有下列情况:
1. TCP客户没有收到SYN分节的相应,返回ETIMEOUT错误。
2. 客户的SYN的相应是RST,表明该服务器在指定端口没有进程在等待连接,返回ECONNREFUSED错误。
3. 客户发出的SYN在中间的某个路由器引发了一个destination unreachable``ICMP错误,在规定的时间内仍未收到相应,返回EHOSTUNREACH错误。

connect失败,该套接字不可再使用,必须关闭。我们不能再对该套接字调用connect

bind函数

    #include <sys/socket.h>    int bind(int sockfd, const struct sockaddr *myaddr, socklent_t addrlen);

bind函数把一个本地协议地址赋予一个套接字。
要注意是否指定IP地址或端口产生的行为。如果让内核为套接字选择一个临时端口号,bind函数不返回选择的值(第二个参数有const修饰),需要调用函数getsockname来返回协议地址。

listen函数

    #include <sys/socket.h>    int listen(int sockfd, int backlog);

当socket函数创建一个套接字时,它被假设为一个主动套接字(将调用connect发起连接)。listen函数把一个未连接的套接字转换为一个被动套接字。
要理解第二个参数,需认识到内核为监听套接字维护的两个队列:
+ 未完成连接队列
+ 已完成连接队列
当一个客户SYN到达时,若这些队列是满的,TCP就忽略该分节(为什么)。

accept函数

    #include <sys/socket.h>    int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

第一个参数为监听套接字。若accept成功,则返回已连接套接字。注意区分两者(生命期)。

close函数

    #include <sys/socket.h>    int close(int sockfd);

getsockname和getpeername函数

    #include <sys/socket.h>    int getsockname(int sockfd, struct sockaddr *localaddr, socketlen_t *addrlen);    int getpeername(int sockfd, struct sockaddr *peeraddr, socketlen_t *addrlen);

例程:接受连接并显示客户地址

    //server.c    #include    "unp.h"    #include    <time.h>    int    main(int argc, char **argv)    {        int                 listenfd, connfd;        socklen_t           len;        struct sockaddr_in  servaddr, cliaddr;        char                buff[MAXLINE];        time_t              ticks;        size_t i;        listenfd = Socket(AF_INET, SOCK_STREAM, 0);        bzero(&servaddr, sizeof(servaddr));        servaddr.sin_family      = AF_INET;        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);        servaddr.sin_port        = htons(13);   /* daytime server */        Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));        Listen(listenfd, LISTENQ);        for ( ; ; ) {            len = sizeof(cliaddr);            connfd = Accept(listenfd,(SA *)&cliaddr,&len);            printf("connection from %s, port %d\n",                   inet_ntop(AF_INET,&cliaddr.sin_addr,buff,sizeof(buff)),                   ntohs(cliaddr.sin_port));            ticks = time(NULL);            snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));    //        for(i = 0;i<strlen(buff);++i){    //            Write(connfd,buff[i],1);    //        }            Write(connfd, buff, strlen(buff));            Close(connfd);        }    }    //client.c    #include    "unp.h"    int    main(int argc, char **argv)    {        int                 sockfd, n;        char                recvline[MAXLINE + 1];        struct sockaddr_in  servaddr;        int counter=0;        if (argc != 2)            err_quit("usage: a.out <IPaddress>");        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)            err_sys("socket error");        bzero(&servaddr, sizeof(servaddr));        servaddr.sin_family = AF_INET;        servaddr.sin_port   = htons(13);    /* daytime server */        if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)            err_quit("inet_pton error for %s", argv[1]);        if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)            err_sys("connect error");        while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {            counter++;            recvline[n] = 0;    /* null terminate */            if (fputs(recvline, stdout) == EOF)                err_sys("fputs error");        }        if (n < 0)            err_sys("read error");        //printf("counter = %d\n",counter);        exit(0);    }

运行服务器程序server,然后再同一主机上运行客户程序:

./client 127.0.0.1./client 127.0.0.2

得到相应的服务器输出:

connection from 127.0.0.1, port 48235connection from 127.0.0.1, port 48236
0 0
原创粉丝点击