网络字节序的转换
- TCP/IP协议规定:网络字节流采用大端字节序(电脑中一般是小段存储)
(1):大端:低地址 -> 高字节
(1):小端:低地址 -> 低字节 - linux下的转换函数
(1)字节序的转换
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);//本地(host)到网络 (network)ip
uint16_t htons(uint16_t hostshort); // 本地到网络 port
uint32_t ntohl(uint32_t netlong); //网络到本地 ip
uint16_t ntohs(uint16_t netshort); //网络到本地port
(2)字符串IP和网络字节序转换
#include<arpa/inet.h>
/*af: IP版本 AF_INET->Ipv4 AF_INET->Ipv6
src:要转的字符串
dst:网络地址的结构体指针
*/
int inet_pton(int af, const char *src, void *dst);//字符串 -> 网络字节序
/*af: IP版本 AF_INET->Ipv4 AF_INET->Ipv6
src:要转的网络字节序
dst:指向存放ip字符串的buf
size:buf的大小
*/
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);//网络字节序 -> 字符串
- sockaddr数据结构
在申明结构体的时候使用sockaddr_in,在传递参数的时候使用强制转换(sockaddr *)
//以前版本
struct sockaddr
{
sa_family_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
//现在版本
struct sockaddr_in
{
sa_family_t sin_family; /* Address family : AF_INET*/ 地址结构类型
in_port_t sin_port; /* Port number in network byte order */ 端口号
struct in_addr sin_addr; /* Internet address */ IP地址
};
struct in_addr
{
uint32_t s_addr; /* Internet address in network byte order*/
};
- 实现C/S模型常用函数(man 2 查看)
(1)socket函数:创建套接字
/*
domain: AF_INET | AF_INET6 | AF_UNIX(本地)
type: SOCK_STREAM(流式) | SOCK_DGRAM(报式)
protocol: 0( 默认)
成功:返回指向新创建的socket的文件描述符
*/
socket(int domain, int type, int protocol)
(2)bind函数:绑定IP+Port
/*
sockfd:需要绑定的socket文件描述符
addr:IP+port结构体地址
addrlen:结构体大小
*/
bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
(3)listen函数:服务器同时允许客户端建立连接的数目
/*
sockfd : socket文件的描述符
backlog : 指定同时建立连接的客户端数目
*/
listen(int sockfd, int backlog)
(4)accept函数:接收一个socket连接请求
/*
sockfd:自己用socket创建的套接字返回的本地文件描述符
addr: 传出参数,socket 结构体(用来存放客户端IP+Port信息)
addrlen: 传入、传出参数,传入addr结构体的大小,传出真正的结构体内部大小
返回值:套接字文件描述符(用来和客户端通信的)
*/
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
(5)connect函数:客户端建立连接
/*
sockfd: 客户端本地的socket文件描述符
addr:服务器的IP+Port结构体信息
addrlen:传入参数 sizeof(addr)
成功返回0
*/
connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
- 实现C/S模型流程图
例子:server.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <arpa/inet.h>
7 #include <ctype.h>
8
9 #define port 9999
int main(void)
12 {
13
14 int lfd,cfd;
15 struct sockaddr_in server_addr, client_addr;
16 char buf[256]={0}, client_buf[256]={0};
17
18 lfd = socket(AF_INET, SOCK_STREAM,0 ); // creat socket
19 if(lfd==-1)
20 {
21 perror("socket error");
22 return;
23 }
server_addr.sin_family = AF_INET;
27 server_addr.sin_port = htons(port);//transfer port to net sequence
28 // inet_pton(AF_INET,ipv4,&server_addr.sin_addr);//transfer ip to net sequence
30 server_addr.sin_addr.s_addr=htonl(INADDR_ANY); //INADDR_ANY自动获取有效ip
31 int tmp2=bind(lfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); // specify socket with ip and port
32 if(tmp2<0)
33 {
34 perror("bind error");
35 return;
36 }
37
38
39
40 int tmp3=listen(lfd,128); // specify max client connected simultaneously
41 if (tmp3<0)
42 {
43 perror(" listen error");
44 return;
45 }
46
47 printf("wait for client connect.....\n");
48
49 socklen_t len=sizeof(client_addr);
50 cfd=accept(lfd,(struct sockaddr*)&client_addr,&len); //accept a requirment for connection
51 //打印client的ip和端口
printf("client ip:%s\t port:%d\n",
53 inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_buf,sizeof(client_buf)),
54 ntohs(client_addr.sin_port));
55
56 while(1)
57 {
58 int n=read(cfd,buf,sizeof(buf)); //从socket文件描述符中 读数据
59 if(n!=0)
60 { int i=0;
61 for( i=0;i<n;i++)
62 {
63 buf[i]=toupper(buf[i]); // 转成大写字符
64 }
65 write(cfd,buf,n); //写入socket文件描述符,返回给client
66 }
67 }
68
69
70 close(cfd);
71 close(lfd);
72
73 return 0;
74 }
client.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/socket.h>
5 #include <arpa/inet.h>
6 #include <string.h>
7
8 #define SERV_IP "127.0.0.1"
9 #define SERV_PORT 9999
11 int main(void)
12 {
13
14 int cfd;
15 struct sockaddr_in serv_addr;
16 char buf[64]={0};
17 int n=0;
18
19 cfd=socket(AF_INET,SOCK_STREAM,0); //创建socket 文件
20
21 // socket结构体的赋值
22 memset(&serv_addr,0,sizeof(serv_addr));
23 serv_addr.sin_family=AF_INET;
24 serv_addr.sin_port= htons(SERV_PORT);
25 inet_pton(AF_INET,SERV_IP,&serv_addr.sin_addr.s_addr);
26
// 建立连接
27 connect(cfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
28
//从键盘读入,写入socket文件,再从socket文件读出、显示
29 while(1)
30 {
31 fgets(buf,sizeof(buf),stdin);
32 write(cfd,buf,strlen(buf));
33 n = read(cfd,buf,sizeof(buf));
34 write(STDOUT_FILENO,buf,n);
35 }
36
37 close(cfd);
38 return 0;
39 }
结果:
客户端发送小写字母,服务器转成大写字符再返回,客户端再接收显示