Linux下网络编程
Posted yiya-blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux下网络编程相关的知识,希望对你有一定的参考价值。
目录
1、socket()---用于服务端和客户端
2、bind()---用于服务端 涉及到大端和小端模式
3、listen()---用于服务端
4、accetp()---用于服务端
5、connect()----用于客户端
一、相关协议的介绍
二、socket实现C/S通信
三、常用函数介绍
1、socket()---用于服务端和客户端
函数头文件及函数原型:
1 #include <sys/types.h> /* See NOTES */ 2 #include <sys/socket.h> 3 int socket(int domain, int type, int protocol);
参数及返回值说明:
1 domain: 2 AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址 3 AF_INET6 与上面类似,不过是来用IPv6的地址 4 AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用 5 type: 6 SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。 7 SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。 8 SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。 9 SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议) 10 SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序 11 protocol: 12 传0 表示使用默认协议。 13 返回值: 14 成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno
socket()说明:
1 socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符,应用程序可以像读写文件一样用read/write在网络上收发数据,如果socket()调用出错则返回-1。对于IPv4,domain参数指定为AF_INET。对于TCP协议,type参数指定为SOCK_STREAM,表示面向流的传输协议。如果是UDP协议,则type参数指定为SOCK_DGRAM,表示面向数据报的传输协议。protocol参数的介绍从略,指定为0即可。
2、bind()---用于服务端
函数作用:是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。
函数头文件及函数原型
1 #include <sys/types.h> /* See NOTES */ 2 #include <sys/socket.h> 3 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数及返回值说明:
1 sockfd: 2 socket文件描述符 3 addr: 4 构造出IP地址加端口号 5 addrlen: 6 sizeof(addr)长度 7 返回值: 8 成功返回0,失败返回-1, 设置errno
bind()第二个参数sockaddr是一个结构体,原型如下:
1 struct sockaddr { 2 sa_family_t sin_family;//地址族 3 char sa_data[14]; //14字节,包含套接字中的目标地址和端口信息 4 };
由于sockaddr结构体中的成员sa_data将目标地址(目标IP地址)和端口混在一起了,所以不使用这个结构体,而是要另外一个结构体socketaddr_in,最后将sockaddr_in强制转换一下即可,sockaddr_in结构体原型如下:
1 struct sockaddr_in{ 2 sa_family_t sin_family; //地址族(Address Family) 3 uint16_t sin_port; //16位TCP/UDP端口号 4 struct in_addr sin_addr; //32位ip地址 5 char sin_zero[8]; //不使用 6 }; 7 8 struct in_addr{ 9 In_addr_t s_addr; //32位ipv4地址 10 };
由于在TCP/UDP/IP协议中规定使用大端存储方式(网络自己序),而在我们的电脑中使用的是小端模式,因此需要转换函数,做存储模式的转换:
1 #include <arpa/inet.h> 2 3 //将主机字节序转换为网络字节序 4 unit32_t htonl (unit32_t hostlong); 5 unit16_t htons (unit16_t hostshort); 6 //将网络字节序转换为主机字节序 7 unit32_t ntohl (unit32_t netlong); 8 unit16_t ntohs (unit16_t netshort); 9 10 说明:h -----host;n----network ;s------short;l----long。
使用方法如下:
1 struct sockaddr_in server; 2 memset(&server, 0, sizeof(server)); //先将结构体清零 3 server.sin_family = AF_INET; // 地址类型 - ipv4 4 server.sin_port = htons(8888); 5 server.sin_addr.s_addr = htonl(INADDR_ANY); //htons(a)表示将在主机中的小端存储方式转换为网络中的大端存储方式 s表示shrot 6 int ret = bind(lfd, (struct sockaddr*)&server, sizeof(server)); //同理htonl() l表示long
INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址
3、listen()---用于服务端
头文件及函数原型
1 #include <sys/types.h> /* See NOTES */ 2 #include <sys/socket.h> 3 int listen(int sockfd, int backlog);
参数说明
1 sockfd: 2 socket文件描述符 3 backlog: 4 排队建立3次握手队列和刚刚建立3次握手队列的链接的最大数 5 或者是可以创建连接的最大数
返回值
listen()成功返回0,失败返回-1
listen()函数说明
1 /* 2 典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。 3 */
4、accetp()---用于服务端
头文件即函数原型
1 #include <sys/types.h> /* See NOTES */ 2 #include <sys/socket.h> 3 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明及函数返回值
sockdf: socket文件描述符 addr: 传出参数,返回链接客户端地址信息,含IP地址和端口号 addrlen: 传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小 返回值: 成功返回一个新的socket文件描述符,用于和客户端通信,通过这个读新的文件描述符就可以得到客户端发来的信息,失败返回-1,设置errno
函数说明
1 /* 2 三方握手完成后,服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。addr是一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区addr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者提供的缓冲区)。如果给addr参数传NULL,表示不关心客户端的地址。 3 */
使用方法
1 struct sockaddr_in client; 2 socklen_t len = sizeof(client); 3 int cfd = accept(lfd, (struct sockaddr*)&client, &len); //如果没有客户端请求连接,则阻塞在这里,其中client为传出参数,包含了客户端的ip和端口号 4 if(cfd == -1) 5 { 6 perror("accept error"); 7 exit(1); 8 }
accept()的返回值是另外一个文件描述符connfd,之后与客户端之间就通过这个connfd通讯,最后关闭connfd断开连接,通过cfd读取客户端发来的信息的方法:
1 char buf[1024] = {0}; 2 int len = read(cfd, buf, sizeof(buf)); 3 //len=-1读失败 4 //len=0客户端关闭 5 //len>0读成功
5、connect()----用于客户端
头文件及函数原型
1 #include <sys/types.h> /* See NOTES */ 2 #include <sys/socket.h> 3 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数及函数返回值说明
1 sockdf: 2 socket文件描述符 3 addr: 4 传入参数,指定服务器端地址信息,含IP地址和端口号 5 addrlen: 6 传入参数,传入sizeof(addr)大小 7 返回值: 8 成功返回0,失败返回-1,设置errno
函数说明
1 /* 2 客户端需要调用connect()连接服务器,connect和bind的参数形式一致,区别在于bind的参数是自己的地址,而connect的参数是对方的地址。connect()成功返回0,出错返回-1。 3 */
以上是关于Linux下网络编程的主要内容,如果未能解决你的问题,请参考以下文章