快捷搜索:  汽车  科技

linux网络编程平台(Linux网络编程)

linux网络编程平台(Linux网络编程)有4个函数专门用于转换:大写V,ASCII值为86,对应16进制为56。可以看出电脑上是小端法存储。4字节整数a的存储示意如图所示:写个小程序,把a的最低位输出来,看看是多少。#include<stdio.h> int main(int argc char const *argv[]) { printf("%d\n" sizeof(int) ); unsigned int a=0x12345678; printf("%c\n" a); printf("%c\n" *((char*)&a 1)); printf("%c\n" *((char*)&a 2)); printf("%c\n" *((char*)&a 3)); return 0; }上面程序输出为x,小写x的ASCII值

Socket

一个文件描述符指向一个套接字(套接字内部由内核借助两个缓冲区实现)

linux网络编程平台(Linux网络编程)(1)

网络字节序:

小端法(PC):高位存高地址,地位存地址

大端法(网络):高位存低地址,地位存高地址

TCP/IP协议规定,网络数据流采用大端字节序;而主机当中使用的是小端法,需要做网络字节序和主机字节序的转换。

4字节整数a的存储示意如图所示:

linux网络编程平台(Linux网络编程)(2)

写个小程序,把a的最低位输出来,看看是多少。

#include<stdio.h> int main(int argc char const *argv[]) { printf("%d\n" sizeof(int) ); unsigned int a=0x12345678; printf("%c\n" a); printf("%c\n" *((char*)&a 1)); printf("%c\n" *((char*)&a 2)); printf("%c\n" *((char*)&a 3)); return 0; }

linux网络编程平台(Linux网络编程)(3)

上面程序输出为x,小写x的ASCII值为120,而0x78转换为10进制就是120。

大写V,ASCII值为86,对应16进制为56。可以看出电脑上是小端法存储。

有4个函数专门用于转换:

#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);

h表示host,n表示network,l表示32位,s表示16位。

htonl:本地->网络(IP)

htons:本地->网络(port)

ntohl:网络->本地(IP)

ntohs:网络->本地(port)

IP地址转换函数

inet_pton:点分十进制字符串转换为网络字节序

inet_ntop:网络字节序转换为点分十进制字符串

这两个函数都支持IPv4和IPv6.

#include <arpa/inet.h> int inet_pton(int af const char *src void *dst);

af:表示地址类型,只有两个选择,AF_INET表示IPv4,AF_INET6表示IPv6

src:要转换的IP(点分十进制字符串)

det:转换后的网络字节序的IP地址

返回值:

成功:1

异常:0,表示scr指向的不是一个有效的IP地址

失败:-1

#include <arpa/inet.h> const char *inet_ntop(int af const void *src char *dst socklen_t size)

af:AF_INET、AF_INET6

scr:网络字节序的IP地址

dst:本地字节序(string IP)

size:dst的大小

返回值:

成功:dst

失败:NULL;

https://blog.csdn.net/bian_qing_quan11/article/details/71699371

inet_ntoa:网络字节序转换为点分十进制IP

char *inet_ntoa(struct in_addr in);

inet_aton:点分十进制IP转换为网络字节序存放在addr中,成功返回1,失败返回0。

inet_aton() returns 1 if the supplied string was successfully interpreted or 0 if the string is invalid (errno is not set on
error).

int inet_aton(const char *cp struct in_addr *inp);

inet_network:将点分十进制IP转化为主机字节序(二进制位小端存储)

in_addr_t inet_network(const char *cp);

inet_addr:将点分十进制IP转化为网络字节序(二进制位的大端存储)。

in_addr_t inet_addr(const char *cp);

#include <stdio.h> #include <arpa/inet.h> int main(int argc char const *argv[]) { struct in_addr in; printf("点分十进制ip地址:192.168.1.1\n"); printf("主机字节序:%u\n" inet_network("192.168.1.1")); inet_aton("192.168.1.1" &in); printf("网络字节序:%u\n" in.s_addr); in.s_addr = htonl(inet_network("192.168.1.1")); printf("点分十进制ip地址:%s\n" inet_ntoa(in)); return 0; }

192.168.1.1转换成二进制为11000000 10101000 00000001 00000001,转换为十进制为3 232 235 777‬,大端存储为00000001 00000001 10101000 11000000,即16 885 952‬。

linux网络编程平台(Linux网络编程)(4)

sockaddr数据结构

早期的socket数据结构,sockaddr数据结构其实已经不用了,但因为Linux当中很多函数以前用的这个数据结构,不好对这些函数进行更改,就保留了sockaddr数据结构,它就扮演着void *差不多的角色,用作地址转换中介。例如bind的函数当中参数类型还是sockaddr*类型,使用时需要进行地址类型转换。

linux网络编程平台(Linux网络编程)(5)

int bind(int sockfd const struct sockaddr *addr socklen_t addrlen);

sturct sockaddr_in addr; man 7 ip查看sockaddr_in结构体信息。

addr.sin_family=AF_INT; (sin,socket internet??)

addr.sin_port=htons(9527);

//int dst;

//inet_pton(AR_INET "11.11.11.11" (void*)&dst);

//add.sin_addr.s_addr=dst;

addr.sin_addr.s_addr=htonl(INADDR_ANY);取出系统中有效的任意IP地址,二进制类型。INADDR_ANY是一个宏。

bind(fd (struct sockaddr*)&addr size);

struct sockaddr_in:这个in表示internet,不是进入哈哈(我前两天一直以为是输入,很懵逼)

man 7 ip查看sockaddr_in数据结构

struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ };

linux网络编程平台(Linux网络编程)(6)

sockaddr_un是本地进程通信的数据结构。

socket模型创建流程

linux网络编程平台(Linux网络编程)(7)

socket():创建一个套接字,返回一个文件描述符fd,也叫句柄。

bind():绑定IP 端口

listen():设置监听上线,表示同时能连接的客户端数量

accept():阻塞监听客户端连接

connet(),绑定IP和端口

socket函数

socket()

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

domain:通信协议,AF_INET、AF_INET6、AF_UNIX、AF_NETLINK等

type:数据传输方式,有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW等

protocol:对应协议,当protocol为0时,会自动选择type类型对应的默认协议

正如大家所想,一般情况下有了 af 和 type 两个参数就可以创建套接字了,操作系统会自动推演出协议类型,除非遇到这样的情况:有两种不同的协议支持同一种地址类型和数据传输类型。如果我们不指明使用哪种协议,操作系统是没办法自动推演的。
使用 IPv4 地址,参数 af 的值为 PF_INET。如果使用 SOCK_STREAM 传输数据,那么满足这两个条件的协议只有 TCP,因此可以这样来调用 socket() 函数:

int tcp_socket = socket(AF_INET SOCK_STREAM IPPROTO_TCP); //IPPROTO_TCP表示TCP协议

返回值:成功返回文件描述符,错误返回-1。

/usr/include/x86_64-linux-gnu/bits/socket.h /* Protocol families. */ #define PF_UNSPEC 0 /* Unspecified. */ #define PF_LOCAL 1 /* Local to host (pipes and file-domain). */ #define PF_UNIX PF_LOCAL /* POSIX name for PF_LOCAL. */ #define PF_FILE PF_LOCAL /* Another non-standard name for PF_LOCAL. */ #define PF_INET 2 /* IP protocol family. */ #define PF_AX25 3 /* Amateur Radio AX.25. */ #define PF_IPX 4 /* Novell Internet Protocol. */ #define PF_APPLETALK 5 /* Appletalk DDP. */ #define PF_NETROM 6 /* Amateur radio NetROM. */ #define PF_BRIDGE 7 /* Multiprotocol bridge. */ #define PF_ATMPVC 8 /* ATM PVCs. */ #define PF_X25 9 /* Reserved for X.25 project. */ #define PF_INET6 10 /* IP version 6. */ #define PF_ROSE 11 /* Amateur Radio X.25 PLP. */ #define PF_DECnet 12 /* Reserved for DECnet project. */ #define PF_NETBEUI 13 /* Reserved for 802.2LLC project. */ #define PF_SECURITY 14 /* Security callback pseudo AF. */ #define PF_KEY 15 /* PF_KEY key management API. */ #define PF_NETLINK 16 #define PF_ROUTE PF_NETLINK /* Alias to emulate 4.4BSD. */ #define PF_PACKET 17 /* Packet family. */ #define PF_ASH 18 /* Ash. */ #define PF_ECONET 19 /* Acorn Econet. */ #define PF_ATMSVC 20 /* ATM SVCs. */ #define PF_RDS 21 /* RDS sockets. */ #define PF_SNA 22 /* Linux SNA Project */ #define PF_IRDA 23 /* IRDA sockets. */ #define PF_PPPOX 24 /* PPPoX sockets. */ #define PF_WANPIPE 25 /* Wanpipe API sockets. */ #define PF_LLC 26 /* Linux LLC. */ #define PF_IB 27 /* Native InfiniBand address. */ #define PF_MPLS 28 /* MPLS. */ #define PF_CAN 29 /* Controller Area Network. */ #define PF_TIPC 30 /* TIPC sockets. */ #define PF_BLUETOOTH 31 /* Bluetooth sockets. */ #define PF_IUCV 32 /* IUCV sockets. */ #define PF_RXRPC 33 /* RxRPC sockets. */ #define PF_ISDN 34 /* mISDN sockets. */ #define PF_PHONET 35 /* Phonet sockets. */ #define PF_IEEE802154 36 /* IEEE 802.15.4 sockets. */ #define PF_CAIF 37 /* CAIF sockets. */ #define PF_ALG 38 /* Algorithm sockets. */ #define PF_NFC 39 /* NFC sockets. */ #define PF_VSOCK 40 /* vSockets. */ #define PF_KCM 41 /* Kernel Connection Multiplexor. */ #define PF_QIPCRTR 42 /* Qualcomm IPC Router. */ #define PF_SMC 43 /* SMC sockets. */ #define PF_MAX 44 /* For now.. */

/* Address families. */ #define AF_UNSPEC PF_UNSPEC #define AF_LOCAL PF_LOCAL #define AF_UNIX PF_UNIX #define AF_FILE PF_FILE #define AF_INET PF_INET #define AF_AX25 PF_AX25 #define AF_IPX PF_IPX #define AF_APPLETALK PF_APPLETALK #define AF_NETROM PF_NETROM #define AF_BRIDGE PF_BRIDGE #define AF_ATMPVC PF_ATMPVC #define AF_X25 PF_X25 #define AF_INET6 PF_INET6 #define AF_ROSE PF_ROSE #define AF_DECnet PF_DECnet #define AF_NETBEUI PF_NETBEUI #define AF_SECURITY PF_SECURITY #define AF_KEY PF_KEY #define AF_NETLINK PF_NETLINK #define AF_ROUTE PF_ROUTE #define AF_PACKET PF_PACKET #define AF_ASH PF_ASH #define AF_ECONET PF_ECONET #define AF_ATMSVC PF_ATMSVC #define AF_RDS PF_RDS #define AF_SNA PF_SNA #define AF_IRDA PF_IRDA #define AF_PPPOX PF_PPPOX #define AF_WANPIPE PF_WANPIPE #define AF_LLC PF_LLC #define AF_IB PF_IB #define AF_MPLS PF_MPLS #define AF_CAN PF_CAN #define AF_TIPC PF_TIPC #define AF_BLUETOOTH PF_BLUETOOTH #define AF_IUCV PF_IUCV #define AF_RXRPC PF_RXRPC #define AF_ISDN PF_ISDN #define AF_PHONET PF_PHONET #define AF_IEEE802154 PF_IEEE802154 #define AF_CAIF PF_CAIF #define AF_ALG PF_ALG #define AF_NFC PF_NFC #define AF_VSOCK PF_VSOCK #define AF_KCM PF_KCM #define AF_QIPCRTR PF_QIPCRTR #define AF_SMC PF_SMC #define AF_MAX PF_MAX

/usr/include/x86_64-linux-gnu/bits/socket_type.h /* Types of sockets. */ enum __socket_type { SOCK_STREAM = 1 /* Sequenced reliable connection-based byte streams. */ #define SOCK_STREAM SOCK_STREAM SOCK_DGRAM = 2 /* Connectionless unreliable datagrams of fixed maximum length. */ #define SOCK_DGRAM SOCK_DGRAM SOCK_RAW = 3 /* Raw protocol interface. */ #define SOCK_RAW SOCK_RAW SOCK_RDM = 4 /* Reliably-delivered messages. */ #define SOCK_RDM SOCK_RDM SOCK_SEQPACKET = 5 /* Sequenced reliable connection-based datagrams of fixed maximum length. */ #define SOCK_SEQPACKET SOCK_SEQPACKET SOCK_DCCP = 6 /* Datagram Congestion Control Protocol. */ #define SOCK_DCCP SOCK_DCCP SOCK_PACKET = 10 /* Linux specific way of getting packets at the dev level. For writing rarp and other similar things on the user level. */ #define SOCK_PACKET SOCK_PACKET /* Flags to be ORed into the type parameter of socket and socketpair and used for the flags parameter of paccept. */ SOCK_CLOEXEC = 02000000 /* Atomically set close-on-exec flag for the new descriptor(s). */ #define SOCK_CLOEXEC SOCK_CLOEXEC SOCK_NONBLOCK = 00004000 /* Atomically mark descriptor(s) as non-blocking. */ #define SOCK_NONBLOCK SOCK_NONBLOCK };

/usr/include/linux/in.h #if __UAPI_DEF_IN_IPPROTO /* Standard well-defined IP protocols. */ enum { IPPROTO_IP = 0 /* Dummy protocol for TCP */ #define IPPROTO_IP IPPROTO_IP IPPROTO_ICMP = 1 /* Internet Control Message Protocol */ #define IPPROTO_ICMP IPPROTO_ICMP IPPROTO_IGMP = 2 /* Internet Group Management Protocol */ #define IPPROTO_IGMP IPPROTO_IGMP IPPROTO_IPIP = 4 /* IPIP tunnels (older KA9Q tunnels use 94) */ #define IPPROTO_IPIP IPPROTO_IPIP IPPROTO_TCP = 6 /* Transmission Control Protocol */ #define IPPROTO_TCP IPPROTO_TCP IPPROTO_EGP = 8 /* Exterior Gateway Protocol */ #define IPPROTO_EGP IPPROTO_EGP IPPROTO_PUP = 12 /* PUP protocol */ #define IPPROTO_PUP IPPROTO_PUP IPPROTO_UDP = 17 /* User Datagram Protocol */ #define IPPROTO_UDP IPPROTO_UDP IPPROTO_IDP = 22 /* XNS IDP protocol */ #define IPPROTO_IDP IPPROTO_IDP IPPROTO_TP = 29 /* SO Transport Protocol Class 4 */ #define IPPROTO_TP IPPROTO_TP IPPROTO_DCCP = 33 /* Datagram Congestion Control Protocol */ #define IPPROTO_DCCP IPPROTO_DCCP IPPROTO_IPV6 = 41 /* IPv6-in-IPv4 tunnelling */ #define IPPROTO_IPV6 IPPROTO_IPV6 IPPROTO_RSVP = 46 /* RSVP Protocol */ #define IPPROTO_RSVP IPPROTO_RSVP IPPROTO_GRE = 47 /* Cisco GRE tunnels (rfc 1701 1702) */ #define IPPROTO_GRE IPPROTO_GRE IPPROTO_ESP = 50 /* Encapsulation Security Payload protocol */ #define IPPROTO_ESP IPPROTO_ESP IPPROTO_AH = 51 /* Authentication Header protocol */ #define IPPROTO_AH IPPROTO_AH IPPROTO_MTP = 92 /* Multicast Transport Protocol */ #define IPPROTO_MTP IPPROTO_MTP IPPROTO_BEETPH = 94 /* IP option pseudo header for BEET */ #define IPPROTO_BEETPH IPPROTO_BEETPH IPPROTO_ENCAP = 98 /* Encapsulation Header */ #define IPPROTO_ENCAP IPPROTO_ENCAP IPPROTO_PIM = 103 /* Protocol Independent Multicast */ #define IPPROTO_PIM IPPROTO_PIM IPPROTO_COMP = 108 /* Compression Header Protocol */ #define IPPROTO_COMP IPPROTO_COMP IPPROTO_SCTP = 132 /* Stream Control Transport Protocol */ #define IPPROTO_SCTP IPPROTO_SCTP IPPROTO_UDPLITE = 136 /* UDP-Lite (RFC 3828) */ #define IPPROTO_UDPLITE IPPROTO_UDPLITE IPPROTO_MPLS = 137 /* MPLS in IP (RFC 4023) */ #define IPPROTO_MPLS IPPROTO_MPLS IPPROTO_RAW = 255 /* Raw IP packets */ #define IPPROTO_RAW IPPROTO_RAW IPPROTO_MAX }; #endif

bind()

int bind(int sockfd const struct sockaddr *addr socklen_t addrlen);

给socket绑定一个地址结构(IP 端口号),socket和sockaddr_in中的地址结构AF_INT等得一样。

sockfd:socket函数返回值,文件描述符

sturct sockaddr_in addr;

addr.sin_family=AF_INT;

addr.sin_port=htons(9527);

addr.sin_addr.s_addr=htonl(INADDR_ANY);

addr:(struct sockaddr&)&addr,是传入参数

addlen:sizeof(addr),地址结构的大小

返回值:

成功:0;失败:-1

listen()

int listen(int sockfd int backlog);

设置能够同时与服务器建立连接的客户端上线(同时进行3次握手的客户端数量)

sockfd:socket函数返回值,文件描述符

backlog:上限数值,最大为128。

返回值:

成功:0;失败:-1

accept()

int accept(int sockfd struct sockaddr *addr socklen_t *addrlen);

阻塞等待客户端建立连接,成功时返回一个与客户端成功连接的socket文件描述符

sockfd:最开始建立的socket文件描述符

addr:传出参数,成功与服务器建立连接的那个客户端的地址结构(IP port)

addrlen:传入传出参数。入:addr的大小,出:客户端addr的实际大小。

socklen_t clit_addr_len = sizeof(struct sockaddr),传入参数&clit_addr_len。

返回值:

成功,返回新建立的socket的文件描述符,非负整数

失败:-1

connect()

int connect(int sockfd const struct sockaddr *addr socklen_t addrlen);

与服务器建立连接

sockfd:socket函数返回值

addr:传入参数,服务器地址结构

addrlen:服务器地址结构长度

返回值:成功0,失败-1。

如果不使用bind绑定客户端地址结构,系统会“隐式绑定”。

一个简单的例子,

客户端给服务器发一串字符串,服务器将接受到字符串转换为大写,再发功给客户端。

这里用的read、write函数,和recv、send区别后面再研究。

linux网络编程平台(Linux网络编程)(8)

//server.c #include<stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define SERVER_PORT 12345 void sys_error(const char *str) { perror(str); exit(-1); } int main(int argc char const *argv[]) { int sfd cfd ret=0; socklen_t client_addr_len; char buf[1024]; char client_IP[16]; struct sockaddr_in server_addr client_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr=htonl(INADDR_ANY); sfd = socket(AF_INET SOCK_STREAM 0); if(sfd==-1) { sys_error("socket error"); } ret = bind(sfd (struct sockaddr*)&server_addr sizeof(server_addr)); if(ret==-1) { sys_error("bind error"); } ret = listen(sfd 128); if(ret==-1) { sys_error("listen error"); } client_addr_len = sizeof(client_addr); cfd = accept(sfd (struct sockaddr*)&client_addr &client_addr_len); if(cfd==-1) { sys_error("accept error"); } //打印连接上的客户端IP和端口号 printf("client_ip:%s port:%d\n" inet_ntop(AF_INET &client_addr.sin_addr.s_addr client_IP sizeof(client_IP)) ntohs(client_addr.sin_port) ); while(1) { ret = read(cfd buf sizeof(buf)); write(STDOUT_FILENO buf ret); for(int i=0;i<ret;i ) { buf[i] = toupper(buf[i]); } write(cfd buf ret); } close(sfd); close(cfd); return 0; }

还没有写客户端,可以nc命令模拟客户端

linux网络编程平台(Linux网络编程)(9)

linux网络编程平台(Linux网络编程)(10)

#include<stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #define SERVER_PORT 12347 void sys_error(const char *str) { perror(str); exit(-1); } int main(int argc char const *argv[]) { int cfd ret=0; char buf[1024]; struct sockaddr_in client_addr server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); //server_addr.sin_addr.s_addr=htonl(INADDR_ANY); inet_pton(AF_INET "127.0.0.1" &server_addr.sin_addr.s_addr); cfd = socket(AF_INET SOCK_STREAM 0); if(cfd==-1) { sys_error("socket error"); } ret = connect(cfd (struct sockaddr*)&server_addr sizeof(server_addr)); if(ret==-1) { sys_error("connect error"); } while(1) { //scanf("%s" buf); gets(buf);//最好使用fgets。 write(cfd buf strlen(buf)); ret = read(cfd buf sizeof(buf)); write(STDOUT_FILENO buf ret); printf("\n"); } close(cfd); return 0; }

TCP三次握手,对应的函数就是accept,connect。

猜您喜欢: