一 、流程
二、网络字节序
uint32_t htonl(uint32_t hostlong) //本地字节序转网络字节序(IP)
uint16_t htons(unit16_t hsoshort) //本地字节序转网络字节序(端口)
uint32_t ntohl(unit32_t netlong) //网络字节序转本地字节序(端口)
uint16_t ntohs(unit16_t netshort) //网络字节序转本地字节序(端口)
IP地址转换函数(常用的)
int inet_pton(int af, const char *src, void *dst)
把点分十进制的ip转换为网络字节序
af:当前的ip协议类型AF_INET AF_INET6
src:传入参数 IP地址(点分十进制)
dst:传出参数 转换后的网络字节序的IP地址
成功返回1 异常返回0(src指向的不是有效的IP地址) 失败返回-1
const char *inet_ntop(int af, const void *src,
char *dst, socklen_t size)
把网络字节序转换为本地字节序
af:AF_INET AF_INET6
src: 传入参数 网络字节序IP地址
dst:传出参数 本地字节序(string IP)
size:字节序的大小
三、函数API
1、
struct sockaddr
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 */
};
初始化的时候用下面的结构体初始化,传参的时候在强转为上面结构体的指针
成员初始化:
sin_family :AF_INET/AF_INET6(ipv4/ipv6)
sin_port:网络字节序的端口号
sin_addr.s_addr:(结构体嵌套结构体)网络字节序的IP地址 一般情况下赋值方法为
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
自动取当前系统中有效的IP地址。 默认整形,进行字节序转换
2、
int socket(int domain, int type, int protocol)
socket函数:创建一个套接字
domain:选用的IP地址协议 通常为AF_INET(IPV4)、AF_INET6(IPV6)。
type:创建套接字所选用的数据传输协议 SOCK_STREAM、SOCK_DGRAM
protocol:所选用的协议的代表协议,默认为0(根据前面的所选的类型自动确定)(TCP/UDP)
返回值:成功:新套接字所对应的文件描述符 。失败:返回-1。
3、
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
bind:给socket绑定地址结构(IP + 端口号)
sockfd:socket函数的返回值
addr:传入参数(struct sockaddr *)&addr (进行强转)
addrlen:sizeof(addr)地址结构的大小
返回值:成功:0 。 失败-1。
4、
int listen(int sockfd, int backlog)
listen:设置同时与服务器链接的上限数(同时进行三次握手的客户端数量)
sockfd:socket函数的返回值
backlog:同时连接的数值
5、
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
accept:阻塞等待客户端连接,成功返回一个与客户端链接的socket文件描述符(新的文件描述符)
sockfd:socked函数的返回值。
addr:传出参数。成功与服务器建立链接的客户端的地址结构(IP+PORT)。
addrlen:传入传出参数。入:addr的大小 。 出:客户端addr的实际大小。
clit_addr_len = sizeof(clit_addr);
传参的时候传&clit_addr_len。
返回值:返回能与服务器进行数据通信的socket对应的文件描述符。失败返回-1。
6、
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
connect:与服务器建立连接
sockfd:客户端scoket函数的返回值
addr:传入参数 服务器的地址结构
addrlen:服务器地址结构的大小。
返回值: 成功0 失败-1。
三、代码实现
实现功能:客户端输入小写字符,服务器将小写字母转换为大写字母返回给客户端并打印。
服务器端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<sys/socket.h>
4 #include<string.h>
5 #include<unistd.h>
6 #include<ctype.h>
7 #include<arpa/inet.h>
8
9 #define SERV_PORT 9257
10
11 int main()
12 {
13 int lfd = 0;
14 int cfd = 0;
15 char buf[BUFSIZ], client_IP[1024];
16 //定义结构体并初始化
17 struct sockaddr_in serv_addr, clit_addr;
18 socklen_t clit_addr_len;
19 serv_addr.sin_family = AF_INET;
20 serv_addr.sin_port = htons(SERV_PORT);
21 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
22
23 //创建socket
24 lfd = socket(AF_INET, SOCK_STREAM, 0);
25 if (lfd == -1){
26 perror("socket error");
27 exit(1);
28 }
29
30 //绑定
31 int ret = bind(lfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
32 if (ret == -1){
33 perror("bid error");
34 exit(1);
35 }
36
37 ret = listen(lfd, 128);
38 if (ret == -1){
39 perror("listen error");
40 exit(1);
41 }
42
43 //阻塞监听客户端建立链接 返回新的文件描述符
44 clit_addr_len = sizeof(clit_addr);
45 cfd = accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len);
46 if (cfd == -1){
47 perror("accept error");
48 exit(1);
49 }
50 printf("client ip:%s port:%d\n",
51 inet_ntop(AF_INET, &clit_addr.sin_addr.s_addr, client_IP, sizeof(client_IP)),
52 ntohs(clit_addr.sin_port));
53
54 //服务器工作:读文件
55 int i = 0;
56 while(1){
57 ret = read(cfd, buf, sizeof(buf));
58 write(STDOUT_FILENO, buf, ret);
59 for(i = 0; i < ret; i ++){
60 buf[i] = toupper(buf[i]); //小写转大写
61 }
62 write(cfd, buf, ret);
63 }
64
65 close(cfd);
66 close(lfd);
67 return 0;
68 }
客户端:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<sys/socket.h>
6 #include<arpa/inet.h>
7
8 #define SERV_PORT 9257
9
10 int main()
11 {
12 int cfd;
13 int conter = 10;
14 char buf[BUFSIZ];
15
16 struct sockaddr_in serv_addr; //服务器的地址结构
17 serv_addr.sin_family = AF_INET;
18 serv_addr.sin_port = htons(SERV_PORT);
19 inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
20 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
21
22 cfd = socket(AF_INET, SOCK_STREAM, 0);
23 if (cfd == -1){
24 perror("socket error");
25 exit(1);
26 }
27
28 int ret = connect(cfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr));
29 if (ret != 0){
30 perror("connect error");
31 exit(1);
32 }
33 while(conter--){
34 write(cfd, "hello\n", 6);
35 ret = read(cfd, buf, sizeof(buf));
36 write(STDOUT_FILENO, buf, ret);
37 sleep(1);
38 }
39 close(cfd);
40 return 0;
41 }
42
程序运行结果: