AIRobot

AIRobot quick note


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

Linux socket

发表于 2019-03-19 分类于 linux
本文字数: 19k 阅读时长 ≈ 17 分钟

一、socket编程

网络功能是Uinux/Linux的一个重要特点,有着悠久的历史,因此有一个非常固定的编程套路。

基于TCP的网络编程:

基于连接, 在交互过程中, 服务器和客户端要保持连接, 不能断开。重发一切出错数据、数据验证, 保证数据的正确性、完整性和顺序性,缺点是消耗的资源比较大。

基于UDP的网络编程:

无连接协议, 在网络交互过程中不保持连接, 只需要在发送数据时连接一下, 不重发、验证数据。优点是资源消耗少, 数据的可靠性完整性顺序性得不到保证。

二、编程步骤:

服务器:

  • ① 创建socket(套接字) socket()

  • ② 准备通信地址

  • ③ 将创建的socket和通信地址绑定 bind()

  • ④ 监听端口 listen()

  • ⑤ 等待客户端连接 accpet()

  • ⑥ 通信双方收发数据 read()/write() send()/recv()

  • ⑦ 关闭socket

客户端:

  • ① 创建socket(套接字) socket()

  • ② 准备通信地址

  • ③ 连接服务器 connect()

  • ④ 收发数据 read()/write() send()/recv()

  • ⑤ 关闭socket  

三、API详解

① socket()函数

    int socket(domain, type, protocol)

    domain:

        AF_UNIX/AF_LOCAL/AF_FILE: 本地通信

        AF_INET: 网络通信 ipv4

        AF_INET6: 网络通信 ipv6

        注:如果AF换成PF效果一样

    type, 选择通信类型, 主要包括:

        SOCK_STREAM: TCP

        SOCK_DGRAM : UDP

    protocol, 本来应该指定通信协议, 但现在基本废弃, 因为协议已经在前面两个参数指定完成,给0即可

② bind()函数

    int bind(int sockfd, struct sockaddr *addr, size)

    sockfd: 要绑定的套接字描述符

    size: 第二个参数占据的内存空间大小

    addr: 涉及三个数据结构struct sockaddr, sockaddr_un, sockaddr_in

      sockaddr, 主要用于函数参数, 不负责存储数据

      sockaddr_un, 当着本地通信时, 用于本地通信使用的地址 (sys/un.h)

      sockaddr_in, 当着网络通信时, 负责存储网络通信的地址数据

      struct sockaddr_in {

          sin_family; //用于指定协议族, 和socket()的参数保持一致

          sin_port; //网络通信使用的端口号

          sin_addr; //存储网络通信的ip地址 

      }          

③ htons

④ inet_aton         

⑤ listen()函数

    int listen(int sockfd, int backlog)

     sockfd: 将sockfd参数所标识的套接字为被动模式, 使之可以接受连接请求

     backlog: 表示未决连接请求队列的最大长度, 即允许最多有多少个未决连接请求存在。若服务器的未决连接请求已达到该值, 则客户端通过 connect()连接服务器的操作将返回-1,且error为ECONNREFUSED

⑥ accpet()函数

    int accpet(sockfd, struct sockaddr* addr, socklen_t *addrlen)

     从sockfd参数所标识套接字对应未决连接请求队列中取出的一个连接请求, 同时创建一个新的套接字,用于该连接通信, 返回套接字的描述符

     addr和addrlen 用于输出连接请求发起者的地址信息

     返回值: 为新创建用于和客户端通信的套接字描述符 失败-1, error  

⑦ inet_ntoa

⑧ recv()函数  

   int recv(int sockfd, buf, len, flags)

     flags, 通常取0: 阻塞收取数据

        O_NONBLOCK: 不阻塞, 如果未收到数据, 返回错误信息

     返回值:

        >0, 实际接受数据字节数

        -1 , 出错, error

         0 , 通信的另一端关闭

⑨ send()函数

   int send(int sockfd, buf, len, flags)

     flags: 通常取0, 阻塞发送

     O_NONBLOCK: 不阻塞, 如果未收到数据, 返回错误信息

⑩ connect()函数

   int connect(int sockfd, addr, addr_len)

     参数参考bind() 

TCP简易scp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//
// Created by AIRobot on 2018/5/20.
//

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>


const int HostAddrMaxSize = 256;
const int PathMaxSize = 2048;
const int ServerPort = 2222;
const int MSGBufferSize = 1024;
const int BufferSize = 2048;
const int FileNameMaxSize = 512;

/*
* method = 0 put
* method = 1 get
* ctype = 0 path
* ctype = 1 file
*/
typedef struct
{
int method;
int ctype;
size_t len;
char buf[MSGBufferSize];
}MSG;

char host[HostAddrMaxSize], remote_path[PathMaxSize], local_path[PathMaxSize];

int parse(char *first, char *second) {
char *local, *remote;
int mode = 0;
char *split_char;
local = first;
remote = second;
split_char = strstr(remote, ":");
if (!split_char) {
local = second;
remote = first;
split_char = strstr(remote, ":");
if (!split_char) {
puts("wrong path!");
return -1;
}
mode = 1;
}

int host_length = (int) (split_char - remote);
int remote_path_length = (int) (strlen(remote) - host_length);
int local_path_length = (int) strlen(local);
strncpy(host, remote, host_length);
strncpy(remote_path, split_char + 1, remote_path_length);
strncpy(local_path, local, local_path_length);
host[host_length] = '\0';
remote_path[remote_path_length] = '\0';
local_path[local_path_length] = '\0';
return mode;
}

void split2name(char *path, char *name)
{
char *p = path;
char *t;
while((t = strstr(p, "/")))
p = t+1;
int len = strlen(p);
strncpy(name, p, len);
name[len] = '\0';
}

//

void path_join(char *path, char *file_name, char *new_path)
{
size_t length = strlen(path);
size_t len = strlen(file_name);
strncpy(new_path, path, length);
if(new_path[length-1] != '/')
{
strncpy(&new_path[length], "/", 1);
strncpy(&new_path[length+1], file_name, len);
new_path[length+len+1] = '\0';
}
else
{
strncpy(&new_path[length], file_name, strlen(file_name));
new_path[length+len] = '\0';
}
}

int main(int argc, char **argv) {
if (argc != 3) {
puts("usage: myscp src dest");
return 0;
}
if(sizeof(MSG)>BufferSize)
{
perror("message buffer size > buffer size");
exit(1);
}

int mode, on = 1;
int socket_descriptor;
struct sockaddr_in server_addr;
mode = parse(argv[1], argv[2]);
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(ServerPort);
// puts(local_path);
// puts(host);
// puts(remote_path);

if (inet_aton(host, &server_addr.sin_addr) < 0) {
perror("IP error\n");
exit(1);
}
if ((socket_descriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Error opening socket\n");
exit(1);
}
if (connect(socket_descriptor, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1) {
perror("Error connecting to socket\n");
exit(1);
}
puts("connected");
if (mode == 0) // to remote
{
char file_name[FileNameMaxSize+1], new_path[PathMaxSize];
split2name(local_path, file_name);
path_join(remote_path, file_name, new_path);

MSG first_msg;
first_msg.method = 0;
first_msg.ctype = 0;
first_msg.len = strlen(new_path)+1;
strcpy(first_msg.buf, new_path);

send(socket_descriptor, &first_msg, sizeof(first_msg), 0);
int fd = open(local_path, O_RDONLY);
if (fd < 0) {
perror("open file failed\n");
exit(-1);
}
int total;
MSG msg;
msg.method = 0;
msg.ctype = 1;
while ((total = read(fd, msg.buf, sizeof(msg.buf))) > 0) {
msg.len = total;
if (send(socket_descriptor, &msg, sizeof(MSG), 0) < 0) {
perror("send error\n");
exit(1);
}
}
if (total < 0) {
perror("read error");
exit(1);
}
puts("sent");
close(fd);
} else if (mode == 1) // to local
{
char file_name[FileNameMaxSize+1];
char new_path[PathMaxSize];
int total;
split2name(remote_path, file_name);
path_join(local_path, file_name, new_path);
int fd = open(new_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
perror("open file failed\n");
exit(-1);
}

MSG first_msg;
first_msg.method = 1;
first_msg.ctype = 0;
first_msg.len = strlen(remote_path)+1;
strcpy(first_msg.buf, remote_path);
send(socket_descriptor, &first_msg, sizeof(first_msg), 0);

MSG msg;
char buf[sizeof(MSG)];
while ((total = recv(socket_descriptor, buf, sizeof(MSG), 0)) > 0) {
memcpy(&msg, buf, sizeof(MSG));
if (write(fd, msg.buf, msg.len) < 0) {
perror("write error");
exit(1);
}
}
if (total < 0) {
perror("recv error");
exit(1);
}
puts("got");
close(fd);
}
close(socket_descriptor);


return 0;
}

server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// Created by AIRobot on 2018/5/20.
//

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

const int ServerPort = 2222;
const int BufferSize = 2048;
const int MSGBufferSize = 1024;
const int FileNameMaxSize = 512;

typedef struct
{
int method;
int ctype;
size_t len;
char buf[MSGBufferSize];
}MSG;

int main() {
struct sockaddr_in sin, pin;
int sock_descriptor, temp_sock_descriptor;
socklen_t address_size;
int i, len, pid, on = 1;

sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
if (sock_descriptor == -1) {
perror("call to socket");
exit(1);
}
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(ServerPort);

setsockopt(sock_descriptor, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (bind(sock_descriptor, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
perror("call to bind");
exit(1);
}
if (listen(sock_descriptor, 20) == -1) {
perror("call to listen");
exit(1);
}
printf("Accepting connections ...\n");

while(1) {
temp_sock_descriptor = accept(sock_descriptor, (struct sockaddr *)&pin, &address_size);
if (temp_sock_descriptor == -1) {
perror("call to accept");
exit(1);
}
if ((pid=fork()) < 0){
perror("fork");
exit(1);
} else if (pid == 0) { //child
int length;
close(sock_descriptor);
char buf[sizeof(MSG)];
if((length = recv(temp_sock_descriptor, buf, sizeof(MSG), 0)) > 0) {
MSG first_msg;
memcpy(&first_msg, buf, sizeof(MSG));
char path[FileNameMaxSize];
if(first_msg.method==1&&first_msg.ctype==0) // to client
{
puts(first_msg.buf);
strcpy(path, first_msg.buf);
int fd = open(path, O_RDONLY);
if(fd < 0)
{
perror("open failed");
exit(1);
}
int len;
MSG msg;
msg.method = 0;
msg.ctype = 1;
while((len = read(fd, msg.buf, sizeof(msg.buf))) > 0)
{
msg.len = len;
if(send(temp_sock_descriptor, &msg, sizeof(MSG), 0) < 0)
{
perror("send failed");
exit(1);
}
}
if(len < 0)
{
perror("read failed");
exit(1);
}
// puts(path);
puts("sent");
close(fd);
}else if(first_msg.method==0&&first_msg.ctype==0) // to server
{
strcpy(path, first_msg.buf);
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
perror("open file failed\n");
exit(1);
}
int len;
MSG msg;
while((len = recv(temp_sock_descriptor, buf, sizeof(MSG), 0)) > 0)
{
memcpy(&msg, buf, sizeof(MSG));
if(write(fd, msg.buf, msg.len) < 0)
{
perror("write failed");
exit(1);
}
}
if(len < 0)
{
perror("recv failed");
exit(1);
}
puts("store");
close(fd);
}else
{
perror("unsupport");
exit(1);
}
}
else
{
perror("call to recv");
exit(1);
}

// sleep(10);
close(temp_sock_descriptor);
exit(0);
}
close(temp_sock_descriptor);
}

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//
// Created by AIRobot on 2018/5/20.
//

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

const int ServerPort = 2222;
const int BufferSize = 2048;
const int FileNameMaxSize = 512;

int main() {
struct sockaddr_in sin, pin;
int sock_descriptor, temp_sock_descriptor;
socklen_t address_size;
int i, len, pid, on = 1;
char buf[16384];

sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
if (sock_descriptor == -1) {
perror("call to socket");
exit(1);
}
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(ServerPort);

setsockopt(sock_descriptor, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (bind(sock_descriptor, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
perror("call to bind");
exit(1);
}
if (listen(sock_descriptor, 20) == -1) {
perror("call to listen");
exit(1);
}
printf("Accepting connections ...\n");

while(1) {
temp_sock_descriptor = accept(sock_descriptor, (struct sockaddr *)&pin, &address_size);
if (temp_sock_descriptor == -1) {
perror("call to accept");
exit(1);
}
if ((pid=fork()) < 0){
perror("fork");
exit(1);
} else if (pid == 0) { //child
int length;
close(sock_descriptor);
bzero(buf, sizeof(buf));
if((length = recv(temp_sock_descriptor, buf, sizeof(buf), 0)) > 0) {
send(temp_sock_descriptor, "ack", 4, 0);
char path[FileNameMaxSize], tmp_buf[BufferSize];
bzero(tmp_buf, sizeof(tmp_buf));
bzero(path, sizeof(path));
recv(temp_sock_descriptor, path, sizeof(path), 0);
send(temp_sock_descriptor, "ack", 4, 0);
puts("path:");
puts(path);
if(strcmp(buf, "get")==0)
{
int fd = open(path, O_RDONLY);
if(fd < 0)
{
perror("open failed");
exit(1);
}
int len;
while((len = read(fd, tmp_buf, sizeof(tmp_buf))) > 0)
{
if(send(temp_sock_descriptor, tmp_buf, len, 0) < 0)
{
perror("send failed");
exit(1);
}
}
if(len < 0)
{
perror("read failed");
exit(1);
}
// puts(path);
puts("sent");
close(fd);
}else if(strcmp(buf, "put")==0)
{
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
perror("open file failed\n");
exit(1);
}
int len;
while((len = recv(temp_sock_descriptor, tmp_buf, sizeof(tmp_buf), 0)) > 0)
{
if(write(fd, tmp_buf, len) < 0)
{
perror("write failed");
exit(1);
}
}
if(len < 0)
{
perror("recv failed");
exit(1);
}
puts("store");
close(fd);
}else
{
perror("unsupport");
exit(1);
}
}
else
{
perror("call to recv");
exit(1);
}

// sleep(10);
close(temp_sock_descriptor);
exit(0);
}
close(temp_sock_descriptor);
}

return 0;
}

UDP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 12345
int main()
{
/*1 创建socket*/
int sd = socket(PF_INET, SOCK_DGRAM, 0);
if(sd == -1)
{
perror("socket failed");
exit(-1);
}
/*2 准备地址*/
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(PORT);
inet_aton("192.168.1.100", &addr.sin_addr);
/*3 进行通信*/
char *str = "Message";
sendto(sd, str, strlen(str), 0,
(struct sockaddr *)&addr,
sizeof(addr));
char buf[100] = {0};
int len = sizeof(addr);
recvfrom(sd, buf, sizeof(buf), 0,
(struct sockaddr *) &addr,
&len);
printf("Server:%s\n", buf);
close(sd);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 12345
int main()
{
/*1 创建socket*/
int sd = socket(PF_INET, SOCK_DGRAM, 0);
if(sd == -1)
{
perror("socket failed");
exit(-1);
}
/*2 准备地址*/
struct sockaddr_in addr;
addr.sin_family = PF_INET;
addr.sin_port = htons(PORT);
inet_aton("192.168.1.100", &addr.sin_addr);
/*3 socket addr 绑定*/
int res = bind(sd, (struct sockaddr *)&addr,
sizeof(addr));
if(res == -1)
{
perror("bind failed");
exit(-1);
}
/*4 进行通信*/
while(1)
{
char buf[100] = {0};
struct sockaddr_in fromaddr;
int len = sizeof(fromaddr);
recvfrom(sd, buf, sizeof(buf), 0,
(struct sockaddr *) &fromaddr,
&len);
printf("Client %s:%s\n",
inet_ntoa(fromaddr.sin_addr),
buf);
char *str = "server message";
sendto(sd, str, strlen(str), 0,
(struct sockaddr *)&fromaddr,
sizeof(fromaddr));
}
close(sd);

}
# socket
常见C++面试题
多边形求最小面积
  • 文章目录
  • 站点概览
AIRobot

AIRobot

AIRobot quick note
130 日志
15 分类
23 标签
GitHub E-Mail
Creative Commons
  1. 1. 一、socket编程
    1. 1.1. 基于TCP的网络编程:
    2. 1.2. 基于UDP的网络编程:
    3. 1.3. 二、编程步骤:
      1. 1.3.1. 服务器:
      2. 1.3.2. 客户端:
  2. 2. 三、API详解
    1. 2.1. ① socket()函数
    2. 2.2. ② bind()函数
    3. 2.3. ③ htons
    4. 2.4. ④ inet_aton         
    5. 2.5. ⑤ listen()函数
    6. 2.6. ⑥ accpet()函数
    7. 2.7. ⑦ inet_ntoa
    8. 2.8. ⑧ recv()函数  
    9. 2.9. ⑨ send()函数
    10. 2.10. ⑩ connect()函数
  3. 3. TCP简易scp
  4. 4. UDP
0%
© 2023 AIRobot | 716k | 10:51