Linux学习笔记之---基于TCP的通信程序的设计

12:基于TCP的通信程序的设计
    12.1    套接字的类型
            1.流套接字SOCK_STREAM
            是双向的,可靠的,顺序的,不重复的,面向连接的,tcp协议
        
            2.数据报套接字SOCK_DGRAM
            无连接,独立的,无序的,不保证可靠性,udp协议
            
            3.原始套接字SOCK_RAW
            用于底层开发,一般不用
    12.2    socket的创建
            #include <sys/types.h>
            #include <sys/socket.h>
            int socket(int domain, int type, int protocol);
            函数socket创建一个socket描述符,domain指定发送通信的域,即套接字的
            协议族,每个协议族对应一个以“AF_"开头的宏常量:
            AF_UNIX         本地主机通信,功能与IPC对象类似     
            AF_INET         internet地址IPV4协议
            (在实践中只使用第二种)
            参数type指定了通信的类型:
            SOCK_STREAM, SOCK_DGRAM, SOCK_RAW
            protocal指定了该套接字描述符上的一个特殊协议,比如TCP,UDP一般设置为0
            调用成功返回套接字的描述符,否则-1,并置errno
            
            例1:创建AF_INET协议族上的流套接字描述符
            socket(AF_INET, SOCK_STREAM, 0);
            因为流套接字底层通信协议是TCP,所以以上语句等同于:
            socket(AF_INET,SOCK_STREAM,TCP);
            
    12.3    socket的命名--系统调用bind
            #include <sys/types.h>
            #include <sys/socket.h>
            int bind(int s, const struct sockaddr *name, int namelen);
            参数s指定了套接字描述符,这个值由函数socket返回,指针name指向通用套接字
            的协议地址结构,包括协议,地址,和端口信息等,namelen指定该地址结构的长
            度,一般用“sizeof(sockaddr_in)",调用成功时返回0,或者-1,并置errno
            struct sockaddr
            {
                u_short     sa_family;          协议族
                char        sa_data[14];        最多14字节的协议地址
            };
            sa_data描述协议的地址,比如AF_INET使用sockaddr_in描述套接字的地址信息
            struct sockaddr_in
            {
                short           sin_family;     16位的地址协议族(AF_INET)
                u_short         sin_port;       16位的端口地址
                struct in_addr  sin_addr;       32位的IP地址
                char            sin_zero[8];    预留
            }     
            struct in_addr
            {
                u_long   s_addr;
            };
            成员sin_family的取值含义与sa_famliy相同,成员sin_port指定了创建的端口号
            sin_addr以无符号长整型的方式记载IP地址,
            
            1.ip地址转换
            unsigned long inet_addr(char *ptr);
            int inet_aton(char *ptr,struct in_addr *addrptr);
            char *inet_ntoa(struct in_addr inaddr);
            2.字节顺序转换
            #include <sys/types.h>
            #include <netinet/in.h>
            u_long htonl(u_long hostlong);
            u_short htons(u_short hostshort);
            u_long ntohl(u_long netlong);
            u_short ntohs(u_short netshort);
            htons:将16位的整数由主机字节顺序转换成网络字节顺序
            htonl:将32位的整数由主机字节顺序转换成网络字节顺序
            ntohl:将32位的整数由网络字节顺序转换成主机字节顺序
            ntohs:将16位的整数由网络字节顺序转换成主机字节顺序
            例1:将套接字端口1000由主机字节顺序转换为网络字节顺序
            htonl(1000);
            
            例2:命名套接字描述符s的协议为AF_INET,地址为“127.0.0.1”,端口为1000
            struct sockaddr_in sockaddr1;
            memset(&sockaddr1, 0, sizeof(sockaddr1));
            sockaddr1.sin_family = AF_INET;
            sockaddr1.sin_addr.s_addr = inet_addr("127.0.0.1");
            sockaddr1.sin_port = htons(100000);
            bind(s, (struct sockaddr *)&sockaddr1,sizeof(sockaddr));
        
    12.4    socket的侦听--系统调用listen
            #include <sys/types.h>
            #include <sys/socket.h>
            int listen(int s,int backlog);        
            s是创建的套接字,backlog确定了套接字s接收链接的最大数目
            成功返回0,否则返回-1,
            
    12.5    socket的链接处理--系统调用accept
            #include <sys/types.h>
            #include <sys/socket.h>
            int accept(int s, struct sockaddr *addr, int *addrlen);
            成功返回一个与s相同的新的套接字描述符,addr回传连接成功的客户端地址结构
            
    12.6    socket的关闭
            #include <sys/socket.h>
            int shutdown(int s, int how);
                        
    12.7    socket的连接--系统调用connect
            #include <sys/types.h>
            #include <sys/socket.h>
            int connect(int s,const struct sockaddr *name,int namelen);
            s是本地套接字描述符,name指定了对方的套接字地址结构,成功返回0
            
            例1:客户端套接字s向服务器“xxx.xxx.xxx.xxx"提交telnet连接申请(23端口)
            struct sockaddr_in sockaddr1;
            memset(&sockaddr1,0,sizeof(sockaddr1));
            sockaddr1.sin_family = AF_INET;
            sockaddr1.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx.);
            sockaddr1.sin_port = htons(23);
            connect(s, (struct sockaddr *)&sockaddr1,sizeof(sockaddr1));
            
    12.8    TCP数据的发送--系统调用send
            #include <sys/types.h>
            #include <sys/socket.h>
            int send(int s, const void *msg, int len, int flags);
            s是远程地址连接的套接字描述符,msg为待发送的数据消息
            flags是发送标志:
            MSG_OOB             发送外带数据
            MSG_DONTROUTE       通知内核远程IP就在本地局域网内,消息中不加入路由信息
            
            例1:通过套接字s向远程地址发送字符串“hello world“
            send(s,"hello world",strlen("hello world!"),0);
            
    12.9    TCP数据的接收--系统调用recv
            #include <sys/types.h>
            #include <sys/socket.h>
            int recv(int s, void *buf, int len, int flags);
            s是远程地址连接的套接字,buf是存放数据的缓冲区  
            flags是接收标志:
            MSG_OOB         接收外带数据
            MSG_PEEK        只接收而不从缓冲区删除数据
            MSG_WAITALL     阻塞直到读取len字节数据为止
            成功返回接收的数据长度,没有接收到数据或者已经关闭返回0,否则-1
            
    12.10   socket的域名地址        
            域名系统DNS可以实现从域名到IP的转换,以下函数借助域名系统实现此功能
            #include <netdb.h>
            extern int h_errno;
            struct hostent *gethostbyname(const char *name);
            struct hostent *gethostbyaddr(const char *addr, int len, int type);
            void herror(const char *string);
            函数gethostbyname从域名服务器中将字符串形式的域名name转化为网络字节顺序的
            ip地址,如果name就是字符串形式的ip地址,函数直接返回
            hostent存储主机地址信息:
            struct hostent
            {
                char *h_name;           主机的官方名称
                char **h_aliases;       主机的别名
                int  h_addrtype;        地址的类型一般是AF_INET
                int  h_length;          地址占用的字节长度
                char **h_addr_list;     主机的网络字节地址列表
            }
            gethostbyaddr功能相反,type一般为AF_INET
            
    12.11   socket的端口
            以下函数可以显示系统后台进程与其占用的端口之间的关系
            #include <netdb.h>
            struct servent *getservbyname(const char *name, const char *proto);
            struct servent *getservbyport(int port, const char *proto);
            函数getservbyname根据服务名称name获取服务的详细信息,getservbyport根据
            服务器端口号port获取服务的信息,proto是该服务使用的协议名称
            struct servent
            {
                char *s_name;           服务器官方名称
                char **s_aliases;       服务器别名
                int  s_port;            服务器端口号
                char *s_proto;          使用的协议
            };
        
            #include <stdio.h>
            #include <netdb.h>
            #include <sys/types.h>
            #include <netinet/in.h>
            #include <sys/socket.h>
            int main(int argc,char *argv[])
            {
           struct servent *serv;
           if (argc != 2)
           return 1;
           if ((serv = getservbyname(argv[1],"tcp")) == NULL)
           {
           herror("getservbyname");
           return 2;
           }
           printf("Serv name:%s\n",serv->s_name);
           printf("Serv port:%d\n",ntohs(serv->s_port));


           return 0;
            }
            
    12.12   socket的协议地址
            以下函数获取套接字双方的协议地址信息
            int getsockname(int s, struct sockaddr *name, int *namelen);
            int getpeername(int s, struct sockaddr *name, int *namelen);
            函数1获取本地s的sockaddr信息,函数2获取与s相连的对方的sockaddr信息
            
    12.13   套接字选项
            #include <sys/types.h>
            #include <sys/socket.h>
            int getsockopt(int s,int level,int optname,void *optval,int *optlen);     
            int setsockopt(int s,int level,int optname,const void *optval,int optlen);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值