-
Notifications
You must be signed in to change notification settings - Fork 0
/
Socket套接字
235 lines (189 loc) · 7.02 KB
/
Socket套接字
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
http://blog.sina.com.cn/s/blog_a459dcf5010155nf.html
使用Socket时,需要使用到的库:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#pragma comment (lib,"ws2_32.lib"
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
××××××××××××××××××××××××××××××××clinet创建函数
Socket套接字内部的函数:
定义一个套接字socket(int af,int type,int protocal);
参数af用于指定网络地址类型,一般取AF_INET,表示该套接字在Internet域中,进行通信。
参数type用于知道套接字的类型,若取SOCK_STREAM表示创建的套接字是流套接字,而取SOCK_DGRAM创建数字报套接字。
参数protocol用于指定网络协议,一般取0,表示默认为TCP/IP协议。
sockfd=socket(AF_INET,SOCK_STREAM,0)
if(sockfd == -1)
{
printf("Create socket failed.");
}
声明一个结构体对象,来处理网络通信的地址
struct sockaddr_in address;
int len;
memset(&address,0,sizeof(address));
链接套接字配置:
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(ip地址);
address.sin_port= htons(端口号);
//链接服务器
int result = connect(sockfd,(struct sockaddr *)&address,sizeof(address));
if (result==-1)
{
ROS_ERROR("Connect failed");
}
×××××××××××××××××××××××××××××××服务端创建函数
1、首先创建网络通信地址
struct sockaddr_in c_address;
struct sockaddr_in s_address;
memset(&s_address,0,sizeof(s_address));
2创建套接字
s_sockfd = socket(AF_INET,SOCK_STREAM,0)
if(s_sockfd == -1)
{
printf(error);
}
3配置地址链接
s_address.sin_family = AF_INET;
s_address.sin_add.s_addr = INADDR_ANY;
s_address.sin_port = htons(8664);
//bind函数,指定ip端口号
if(bind(s_sockfd,(struct aockaddr *)&s_address, sizeof(s_address))==-1)
{
printf("bind error!");
}
//监听
if (listen(s_socket,1)==-1)
{
printf("socket listen error");
close(s_sockfd);
exit(0);
}
//在socket编程中需要设置套接字为非阻塞时,可以使用fcntl函数设置。
flags = fcntl(s_sockfd,F_GETFL);
if((flags < 0) ||(fcntl(s_sockfd, F_SETFL, flags | O_NONBLOCK) < 0))
{
ROS_INFO("fcntl error");
}
socklen_t len;
// 等待客户端连接
while ((c_sockfd = accept(s_sockfd, (struct sockaddr *)&c_address, &len)) == -1)
{
;
}
如果客户端有链接请求,必须使用下述函数来接收客户端的请求.
accepct(SOCKET s,struct sockaddr FAR *addr, int FAR *addrlen);
addr用于存放客户端的地址,addrlen在调用函数时被设置为addr指向区域的长度,在函数调用结束后被设置为实际地址信息的长度.本函数会阻塞等待知道有客户端请求
达到.
函数的返回值是新的套接字描述符,它代表的是和客户端新的连接,可以把它理解成是一个客户端的socket,这个socket包括的是客户端的Ip和port信息.(当然这个new_socket会从sockfd中继承
服务器的ip和port信息),而参数中的socket s包含的是服务器的ip和port信息.
于是连接之后的send和recv函数中的fd都是指的这个新的new_fd
//接收消息函数:
int recv( SOCKET s, char* buf, int len, int flags );
s是准备接收数据的套接字,buf是即将收到数据的字符缓冲区,而len则是准备接受的字节数或buf缓冲的长度。
flags参数可以是0、MSG_PEEK或MSG_OOB或这些标志的按位“或”运算。
int send( SOCKET s, const char* buf, int len, int flags );
s是已建立连接的套接字描述字,参数buf是字符缓冲区,包含即将发送的数据,参数len用于指定即将发送的缓冲区内的字符数。
flags可取的值有:0、MSG_DONTROUTE或MSG_OOB或这些标志的按位或运算。
ioctl是设备驱动程序中对设备的I/O通道进行管理的函数.所谓管理就是对设备的一些特性进行控制,例如串口的
的传输波特率等。
int ioctl(int fd,int cmd,...);
fd:用户程序打开设备时,使用open函数返回的文件标示符,cmd是用户对设备的控制命令,至于后面的省略号就是一些参数,一般一个,
这个参数与cmd的意义有关系。
ioctl函数是文件结构中的一个属性分量,就是说如果驱动程序提供了ioctl的支持,用户就可以在用户进程中使用ioctl函数来控制设备的I/O通道。
一个客户端和服务端的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void error_handling(char *message);
int main(int argc, char *argv[])
{
int serv_sock;
int clnt_sock;
struct sockaddr_in serv_addr;
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size;
char message[] = "Hello Master HaKu!";
if (argc != 2)
{
printf("Usage: %s <port>\n", argv[0]);
exit(1);
}
serv_sock = socket(AF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
error_handling("sock() error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1]));
if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("bind() error");
if (listen(serv_sock, 5) == -1)
error_handling("listen() error");
clnt_addr_size = sizeof(clnt_addr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if (clnt_sock == -1)
error_handling("accept() error");
write(clnt_sock, message, sizeof(message));
close(clnt_sock);
close(serv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void error_handling(char *message);
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in serv_addr;
char message[30];
int str_len;
if (argc != 3)
{
printf("Usage: %s <IP> <port>\n", argv[0]);
exit(1);
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
error_handling("sock() error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(atoi(argv[2]));
if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("connect() error!");
str_len = read(sock, message, sizeof(message) - 1);
if (str_len == -1)
error_handling("read() error!");
printf("Message from server: %s\n", message);
close(sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
运行方式:
服务端:
gcc hello_server.c -o hserver
./hserver 9999
客户端:
gcc hello_client.c -o hclient
./hclient 127.0.0.1 9999
关于套接字的详细解释:
https://blog.csdn.net/lvyibin890/article/details/80312816