网络编程
1.TCP/UDP对比
- TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前 不需 要建立连接
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等) - 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP首部开销20字节;UDP的首部开销小,只有8个字节
- TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
端口号作用
一台拥有ip地址的主机可以提供许多服务,如web服务、FTP服务、SMTP服务等
实际上是通过“IP地址+端口号”来区 分不同的服务的。
端口提供了一种访问通道,
字节序:指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
Little endian(小端字节序):将低序字节存储在起始地址
Big dendian(大端字节序):将高序字节存储在起始地址
如:
其中0x表示16进制,
LE:低字节序
BE:高字节序
起始地址为4000
字节序转换api
#include <netinet/in.h>
uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值 //一般情况用这个
uint32_t htonl(uint32_t host32bitvalue); //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值
h代表host,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取
转换为中文就是:
地址转换API
int inet_aton(const char* straddr,struct in_addr *addrp);
//把字符串形式的“192.168.1.123”转为网络能识别的格式
char* inet_ntoa(struct in_addr inaddr);
//把网络格式的ip地址转为字符串形式
函数原型:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//
int socket(int domain, int type, int protocol); //创建套接字
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); //获取IP地址和端口号
int listen(int sockfd,int backlog); //监听网络连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //接受连接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //客户端连接主机,与服务器连接
实现双方聊天例子:
server.c
#include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <stdlib.h>
5 //#include <linux/in.h>
6 #include <arpa/inet.h>
7 #include <netinet/in.h>
8 #include <string.h>
9
10 //int socket(int domain, int type, int protocol);
11 //int bind(int sockfd, const struct sockaddr *addr,
12 // socklen_t addrlen);
13 //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
14
15
16 int main()
17 {
18 int s_fd;
19 int n_read;
20 int n_write;
21 char readbuf[128]={0};
22
23 char *buf={"I get meseage for server"};
24 struct sockaddr_in s_addr;.
25 struct sockaddr_in c_addr;
26
27 memset(&s_addr,0,sizeof(struct sockaddr_in));
28 memset(&c_addr,0,sizeof(struct sockaddr_in));
29
30 //1.获取socket
31 s_fd = socket(AF_INET,SOCK_STREAM,0);
32 if(s_fd == -1){
33 perror("socket");
34 exit(-1);
35 }
36 //2.bind() 获取ip地址
37 s_addr.sin_family = AF_INET;
s_addr.sin_port =htons(8988);
39 inet_aton("192.168.60.129",&s_addr.sin_addr);
40 bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr));
41 //3.listen 监听.
42 listen(s_fd,10);
43 //4.accept 接受
44 int clen=sizeof(struct sockaddr);
45 int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
46 if(c_fd == -1){
47 perror("accept");
48 exit(-1);
49 }
50 printf("get connect:%s\n",inet_ntoa(s_addr.sin_addr));
51 //5.read
52 n_read = read(c_fd,readbuf,128); //读数据
53 if(n_read == -1){
54 perror("read");
55 }else{
56 printf("get message:%d %s\n",n_read,readbuf);
57 }
58 //6.write //写数据
59 n_write = write(c_fd,buf,strlen(buf));
60 if(n_write == -1){
61 perror("write");
62 exit(-1);
63 }
64 return 0;
65 }
client.c
#include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <stdlib.h>
5 //#include <linux/in.h>
6 #include <arpa/inet.h>
7 #include <netinet/in.h>
8 #include <string.h>
9
10 //int socket(int domain, int type, int protocol);
11 //int bind(int sockfd, const struct sockaddr *addr,
12 // socklen_t addrlen);
13 //int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
14 // int connect(int sockfd, const struct sockaddr *addr,
15 // socklen_t addrlen);
16
18 int main()
19 {
20 int c_fd;
21 int n_read;
22 char readbuf[128]={0};
23
24 char *buf={"I get meseage fo client"};
25 struct sockaddr_in c_addr;
26
27 memset(&c_addr,0,sizeof(struct sockaddr_in)); //初始化内容
28
29 //1.获取socket
30 c_fd = socket(AF_INET,SOCK_STREAM,0);
31 if(c_fd == -1){
32 perror("socket");
33 exit(-1);
34 }
35 c_addr.sin_family = AF_INET; //因特网域
36 c_addr.sin_port =htons(8988); //端口号
37 inet_aton("192.168.60.129",&c_addr.sin_addr); //把字符串形式的“192.168.60.129”转为网络能识别的格式
39 //2.connect 连接
//与服务器建立连接
40 if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr))==10){
41 perror("connect");
42 exit(-1);
43 }
44
45 //3.send
46 write(c_fd,buf,strlen(buf)); //发数据
47 ....
48 //4.read
49 n_read = read(c_fd,readbuf,128); //读数据
50 if(n_read == -1){
51 perror("read");
52 }else{
53 printf("get message from server:%d %s\n",n_read,readbuf);
54 }
55 //6.write
56 return 0;
57 }
实现多放消息收发例子:
server.c
#include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <stdlib.h>
5 //#include <linux/in.h>
6 #include <arpa/inet.h>
7 #include <netinet/in.h>
8 #include <string.h>
9
10 // int socket(int domain, int type, int protocol);
11 // int bind(int sockfd, const struct sockaddr *addr,
12 // socklen_t addrlen);
13 // int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
14
15 int main(int argc, char **argv) {
16 int s_fd;
17 int c_fd;
18 int n_read;
19 int mark=0;
20 char readbuf[128] = {0};
21
22 // char *buf = {"I get meseage for server"};
23 char buf[128] = {0};
24 struct sockaddr_in s_addr;
25 struct sockaddr_in c_addr;
26
27 memset(&s_addr, 0, sizeof(struct sockaddr_in));
28 memset(&c_addr, 0, sizeof(struct sockaddr_in));
29
30 if (argc != 3) {
31 printf("param no");
32 exit(-1);
33 }
34 // 1.获取socket
35 s_fd = socket(AF_INET, SOCK_STREAM, 0);
36 if (s_fd == -1) {
37 perror("socket");
exit(-1);
39 }
40 // 2.bind() 获取ip地址
41 s_addr.sin_family = AF_INET;
42 s_addr.sin_port = htons(atoi(argv[2]));
43 inet_aton(argv[1], &s_addr.sin_addr);
44 bind(s_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr));
45 // 3.listen 监听
46 listen(s_fd, 10);
47 // 4.accept 接受
48 int clen = sizeof(struct sockaddr);
49 while (1) { //不断的接受
51 c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &clen);
52 if (c_fd == -1) {
53 perror("accept");
54 exit(-1);
55 }
56 mark++;
57 printf("get connect:%s\n", inet_ntoa(s_addr.sin_addr));
58
59 if (fork() == 0) { //创建一个子进程
60 if (fork() == 0) {
61 while (1) { //不断发送数据
62 // 6.write
63 sprintf(buf,"welcome NO.%d client",mark);
64 write(c_fd, buf, strlen(buf)); //发送数据
65 sleep(3);
66 }
67 }
68 while (1) { //不断的读数据
69 // 5.read
70 n_read = read(c_fd, readbuf, 128);
if (n_read == -1) {
72 perror("read");
73 } else {
74 printf("get message:%d %s\n", n_read, readbuf);
75 }
76 }
77 break;
78 }
79 }
80 return 0;
81 }
client.c
#include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <stdlib.h>
5 //#include <linux/in.h>
6 #include <arpa/inet.h>
7 #include <netinet/in.h>
8 #include <string.h>
9
10 // int socket(int domain, int type, int protocol);
11 // int bind(int sockfd, const struct sockaddr *addr,
12 // socklen_t addrlen);
13 // int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
14 // int connect(int sockfd, const struct sockaddr *addr,
15 // socklen_t addrlen);
16
17 int main(int argc, char **argv) {
18 int c_fd;
19 int n_read;
20 char readbuf[128] = {0};
21
22 // char *buf={"I get meseage fo client"};
23 char buf[128] = {0};
24 struct sockaddr_in c_addr;
25
26 memset(&c_addr, 0, sizeof(struct sockaddr_in));
27
28 // 1.获取socket
29 if (argc != 3) {
30 printf("param no");
31 exit(-1);
32 }
33
34 c_fd = socket(AF_INET, SOCK_STREAM, 0); //创建套接字
35 if (c_fd == -1) {
36 perror("socket");
37 exit(-1);
}
39 c_addr.sin_family = AF_INET;
40 c_addr.sin_port = htons(atoi(argv[2]));
41 inet_aton(argv[1], &c_addr.sin_addr);
42
43 // 2.connect 连接
44 if (connect(c_fd, (struct sockaddr *)&c_addr, sizeof(struct sockaddr)) == -1) {
46 perror("connect");
47 exit(-1);
48 }
49 while (1) {
50 if (fork() == 0) {
51 while(1){
52 memset(buf, 0, sizeof(buf));
53 printf("input: \n");
54 gets(buf); //键盘获取发送内容
55 // 3.send
56 write(c_fd, buf, strlen(buf)); //发送
57 }
58 }.
59
60 while(1){
61 // 4.read //读数据
62 n_read = read(c_fd, readbuf, 128);
63 if (n_read == -1) {
64 perror("read");
65 } else {
66 printf("get message from server:%d %s\n", n_read, readbuf);
67 }
68 // 6.write
69 }
70 }
71 return 0;
72 }