面向无连接的套接字通信流程:
服务器:socket(), bind(), recvfrom(), sendto();
客户端:socket(), bind(), sendto(), recvfrom();
面向连接的套接字通信流程:
服务器:socket(), bind(), listen(),
accept(), read(), write();
客户端:socket(), connect(), write(),
read();
系统函数:
#include
#include
int socket(int domain, int type, int protocol);
作用:创建套接字。
参数:domain表示通信使用的协议族,有如下值:
AF_UNIX, AF_LOCAL Local communication
AF_INET IPv4 Internet protocols
AF_INET6 IPv6 Internet protocols
AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device
AF_X25 ITU-T X.25 / ISO-8208 protocol
AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK Appletalk
AF_PACKET Low level packet interface
type表示套接字类型,有如下值:
SOCK_STREAM
SOCK_DGRAM
SOCK_SEQPACKET
SOCK_RAW
SOCK_RDM
SOCK_PACKET
SOCK_NONBLOCK
SOCK_CLOEXEC
protocol表示套接字通信时使用的一个特定协议,通常设置为0。
返回值:文件描述符表示一个新创建的套接字。-1表示失败。errno将被系统设置标明具体的错误。
库函数:
#include
int socket(int domain, int type, int protocol);
作用,参数,返回值同系统函数的int
socket(...);
系统函数:
#include
#include
int setsockopt(int sockfd, int level, int
optname, const void *optval, socklen_t optlen);
作用:设置某个套接字选项的值。
参数:sockfd表示需要设置哪个套接字选项的值。level表示该选项在哪个协议层,通常设置为SOL_SOCKET。optname表示需要设置哪个选项,有如下值:
SO_DEBUG
SO_BROADCAST
SO_REUSEADDR
SO_KEEPALIVE
SO_LINGER
SO_OOBINLINE
SO_SNDBUF
SO_RCVBUF
SO_DONTROUTE
SO_RCVLOWAT
SO_RCVTIMEO
SO_SNDLOWAT
SO_SNDTIMEO
optval表示设置的值由该指针指向。optlen表示设置的值的长度。
返回值:0表示设置成功。-1表示失败。errno将被系统设置标明具体的错误。
库函数:
#include
int setsockopt(int socket, int level, int option_name, const
void *option_value, socklen_t option_len);
作用,参数,返回值同系统函数的intsetsockopt(...);
系统函数:
#include
#include
int getsockopt(int sockfd, int level, int optname, void
*optval, socklen_t *optlen);
作用:获取某个套接字选项的值。
参数:同系统函数的int setsockopt();
返回值:0表示获取成功。-1表示失败。errno将被系统设置标明具体的错误。
库函数:
#include
int getsockopt(int socket, int level, int option_name, void
*restrict option_value, socklen_t *restrict option_len);
作用,参数,返回值同系统函数的int
getsockopt(...);但有更多的选项可以获取,有如下值:
SO_ACCEPTCONN
SO_ERROR
SO_TYPE
系统函数:
#include
#include
ssize_t send(int sockfd, const void *buf, size_t len, int
flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int
flags, const struct sockaddr *dest_addr, socklen_t addrlen);
作用:发送消息到另一个套接字。
参数:sockfd表示源套接字的fd。buf表示要发送的消息。len表示消息的长度。flags可以使用或操作设置为如下值:
MSG_CONFIRM (Since Linux 2.3.15)
MSG_DONTROUTE
MSG_DONTWAIT (since Linux 2.2)
MSG_EOR (since Linux 2.2)
MSG_MORE (Since Linux 2.4.4)
MSG_NOSIGNAL (since Linux 2.2)
MSG_OOB
dest_addr和addrlen的设置情况如下:
If sendto() is used on a connection-mode (SOCK_STREAM,
SOCK_SEQPACKET) socket, the arguments dest_addr and addrlen are
ignored (and the error EISCONN may be returned when they are not
NULL and 0), and the error ENOTCONN is returned when the socket was
not actually connected. Otherwise, the address of the target is
given by dest_addr with addrlen specifying its size.
返回值:实际发送的字符个数。-1表示发送失败。errno将被系统设置标明具体的错误。
额外说明:也可以使用ssize_t write(int fd, const void *buf, size_t
count);将数据写入到套接字中,相当于sendto()
库函数:
#include
ssize_t send(int socket, const void *buffer, size_t length,
int flags);
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr, socklen_t
dest_len);
作用,参数,返回值同系统函数的ssize_t sendto(...);但参数flags仅可以设置为如下值:
MSG_EOR
MSG_OOB
系统函数:
#include
#include
ssize_t recv(int sockfd, void *buf, size_t len, int
flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
作用:从一个套接字接收消息。
参数:sockfd表示接收套接字的fd。buf表示将接收到的数据放在哪(通常是数组)。len表示buf的长度。flags的值如下:
MSG_CMSG_CLOEXEC (recvmsg() only; since Linux 2.6.23)
MSG_DONTWAIT (since Linux 2.2)
MSG_ERRQUEUE (since Linux 2.2)
MSG_OOB
MSG_PEEK
MSG_TRUNC (since Linux 2.2)
MSG_WAITALL (since Linux 2.2)
MSG_EOR
MSG_TRUNC
MSG_CTRUNC
MSG_OOB
MSG_ERRQUEUE
flagssrc_addr和addrlen的设置如下:
Ifsrc_addris
not NULL, and the underlying protocol provides the source address,
this source address is filled in.
Whensrc_addris
NULL, nothing is filled in; in this
case,addrlenis
not used, and should also be NULL. The
argumentaddrlenis
a value-result argument, which the caller should initialize before
the call to the size of the buffer associated
withsrc_addr,
and modified on return to indicate the actual size of the source
address. The returned address is truncated if the buffer provided
is too small; in this case,addrlenwill
return a value greater than was supplied to the call.
返回值:实际接收到的字节数。-1表示失败。If no messages are available to be received
and the peer has performed an orderly shutdown, recvfrom() shall
return 0.errno将被系统设置标明具体的错误。
额外说明:也可以使用ssize_t read(int fd, void *buf, size_t
count);将从套接字中读取数据,相当于recvfrom()
库函数:
#include
ssize_t recv(int socket, void *buffer, size_t
length, int flags);
ssize_t recvfrom(int socket, void *restrict buffer, size_t
length, int flags, struct sockaddr *restrict address, socklen_t
*restrict address_len);
作用,参数,返回值同系统函数的ssize_t recvfrom(...);但参数flags仅可以设置为如下值:
MSG_PEEK
MSG_OOB
MSG_WAITALL
系统函数:
#include
#include
int bind(int sockfd, const struct sockaddr *addr, socklen_t
addrlen);
作用:将套接字与IP地址/端口号绑定。
参数:sockfd表示需要绑定的套接字。addr表示指向sockaddr结构体的指针。addrlen表示sockaddr的长度。
struct sockaddr {
sa_family_t
sa_family;
char sa_data[14];
}
返回值:0表示绑定成功。-1表示失败。errno将被系统设置标明具体的错误。
库函数:
#include
int bind(int socket, const struct sockaddr *address, socklen_t
address_len);
作用,参数,返回值同系统函数的int
bind(...);
系统函数:
#include
#include
int listen(int sockfd, int backlog);
作用:设置套接字接口的监听状态。
参数:sockfd表示需要设置监听状态的套接字。backlog表示能够处理的最大的客户端连接数。
返回值:0表示监听状态设置成功。-1表示失败。errno将被系统设置标明具体的错误。
库函数:
#include
int listen(int socket, int backlog);
作用,参数,返回值同系统函数的int
listen(...);
系统函数:
#include
#include
int accept(int sockfd, struct sockaddr *addr, socklen_t
*addrlen);
作用:接受客户端的连接请求。
参数:sockfd表示监听客户端连接请求的套接字。addr表示指向sockaddr结构体的指针。addrlen表示sockaddr的长度。
struct sockaddr {
sa_family_t
sa_family;
char sa_data[14];
}
返回值:一个非负整数表示用于数据传输的文件描述符。-1表示失败。errno将被系统设置标明具体的错误。
额外说明:函数执行到accept()函数时,会hang住,等待客户端的连接,这时可以通过开启一个新的终端,输入netstat -an
| grep
来查看服务器的状态。之后输入telnet
(相当于一个连接请求)来查看服务器的accept()函数的执行效果。之后输入test send content aaaaaaa
(相当于发送一个字符串)来查看服务器的read()或recvfrom()等函数的执行效果。
库函数:
#include
int accept(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
作用,参数,返回值同系统函数的int
accept(...);
额外说明:Theaccept()
function shall extract the first connection on the queue of pending
connections, create a new socket with the same socket type protocol
and address family as the specified socket, and allocate a new file
descriptor for that socket.
系统函数:
#include
#include
int connect(int sockfd, const struct sockaddr *addr, socklen_t
addrlen);
作用:在客户端的套接字上发送连接请求。
参数:sockfd表示发送连接请求的客户端套接字。addr表示指向sockaddr结构体的指针,sockaddr中存储着服务器的IP地址和端口信息。addrlen表示sockaddr的长度。
struct sockaddr {
sa_family_t
sa_family;
char sa_data[14];
}
返回值:0表示连接成功。-1表示失败。errno将被系统设置标明具体的错误。
库函数;
#include
int connect(int socket, const struct sockaddr *address,
socklen_t address_len);
作用,参数,返回值同系统函数的int
connect(...);
客户端代码:
#include
#include
#include
#include
#include
#include
#include
const char *const socket_name = “my_socket”;
const char *const cmd_edload_test = "edload";
int socket_fd;
struct sockaddr_un serv_addr;
int pass = 0;
int fail = 0;
int open_socket()
{
socket_fd =
socket(AF_LOCAL, SOCK_STREAM, 0);
if
(socket_fd < 0) {
LOGE("Failed to create socket: %s", strerror(errno));
return RET_FAILED;
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sun_family = AF_LOCAL;
//snprintf(serv_addr.sun_path, UNIX_PATH_MAX, "%s",
socket_name);
snprintf(serv_addr.sun_path, 108, "%s", socket_name);
serv_addr.sun_path[0] = 0;
return
RET_SUCCESS;
}
int connect_socket()
{
if
(connect(socket_fd, (struct sockaddr*)
&serv_addr,
offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) != 0)
{
LOGE("Failed to connect to socket: %s", strerror(errno));
close(socket_fd);
return RET_FAILED;
}
return
RET_SUCCESS;
}
int write_data()
{
int
bytes_written;
bytes_written = write(socket_fd, cmd_edload_test,
strlen(cmd_edload_test));
if
(bytes_written < 0) {
LOGE("Failed to write data to socket :%s:", strerror(errno));
close (socket_fd);
return RET_FAILED;
}
return
RET_SUCCESS;
}
int read_data()
{
int
status;
int
bytes_read;
int offset =
0;
do {
bytes_read = read(socket_fd, &status,
sizeof(status) - offset);
if (bytes_read < 0
&& errno != EAGAIN) {
LOGE("Failed to read data from socket: %s", strerror(errno));
return RET_FAILED;
}
offset += bytes_read;
} while
(bytes_read > 0 &&
offset < sizeof(int));
LOGI("Return
status is %d", status);
if (status
== RET_SUCCESS) {
pass ++;
return RET_SUCCESS;
}
LOGE("Failed
to read expected status");
fail
++;
return
RET_FAILED;
}
int close_socket()
{
if
(close(socket_fd) != 0) {
LOGE("Failed to close socket: %s", strerror(errno));
return RET_FAILED;
}