1、socket描述符
•
#include <sys/
socket.h
>
•
int
socket
(
int
domain,
int
type,
int
protocol); #
创建一个
socket
•
参数
domain
,取值:
•
AF_INET
、
AF_INET6
、
AF_UNIX
(本机使用,高级
IPC
部分讲解)
•
参数
type
,取值:
SOCK_DGRAM
、
SOCK_STREAM
、
SOCK_RAW
•
SOCK_DGRAM
类似于信件;
SOCK_STREAM
类似于电话
•
socket
描述符类似于文件描述符,大多操作文件描述符的函数可以操作
socket
描述符
•
如:
read
、
write
、
close
、
dup
、
select
、
poll
•
int
shutdown
(
int
sockfd
,
int
how); #
禁止
IO
•
参数
how
的取值:
SHUT_RD
、
SHUT_WR
、
SHUT_RDWR
2、寻址
•
1
、字节序
•
uint32_t
htonl
(uint32_t hostint32); uint16_t
htons
(uint16_t hostint16);
•
uint32_t
ntohl
(uint32_t netint32); uint16_t
ntohs
(uint16_t netint16);
•
2
、地址格式
•
struct
in_addr
{
•
in_addr_t
s_addr
;} /* IPv4 address */
•
struct
sockaddr_in
{
•
sa_family_t
sin_family
; /* address family */
•
in_port_t
sin_port
; /* port number */
•
struct
in_addr
sin_addr
;} /* IPv4 address */
•
3
、为
socket
绑定地址
•
int
bind
(
int
sockfd
,
const
struct
sockaddr
*
addr
,
socklen_t
len
);
•
int
getsockname
(
int
sockfd
,
struct
sockaddr
*restrict
addr
,
socklen_t
*restrict
alenp
); #
获取
socket
地址信息
•
int
getpeername
(
int
sockfd
,
struct
sockaddr
*restrict
addr
,
socklen_t
*restrict
alenp
); #
获取对端地址信息
3、建立socket连接
•
对于
SOCK_STREAM
类型,需要首先建立连接
•
int
connect
(
int
sockfd
,
const
struct
sockaddr
*
addr
,
socklen_t
len
);
•
服务器必须首先建立侦听队列
•
int
listen
(int sockfd, int backlog);
•
接受客户端连接请求
•
int
accept
(
int
sockfd
,
struct
sockaddr
*restrict
addr
,
socklen_t
*restrict
len
);
4、数据传输
•
ssize_t
send
(
int
sockfd
,
const
void *
buf
,
size_t
nbytes
,
int
flags);
•
ssize_t
sendto
(
int
sockfd
,
const
void *
buf
,
size_t
nbytes
,
int
flags,
const
struct
sockaddr
*
destaddr
,
socklen_t
destlen
);
•
ssize_t
sendmsg
(
int
sockfd
,
const
struct
msghdr
*
msg
,
int
flags);
•
ssize_t
recv
(
int
sockfd
, void *
buf
,
size_t
nbytes
,
int
flags);
•
ssize_t
recvfrom
(
int
sockfd
, void *restrict
buf
,
size_t
len
,
int
flags,
struct
sockaddr
*restrict
addr
,
socklen_t
*restrict
addrlen
);
•
ssize_t
recvmsg
(
int
sockfd
,
struct
msghdr
*
msg
,
int
flags);
5、socket选项
•
int
setsockopt
(
int
sockfd
,
int
level,
int
option,
const
void *
val
,
socklen_t
len
);
•
int
getsockopt
(
int
sockfd
,
int
level,
int
option, void *restrict
val
,
socklen_t
*restrict
lenp
);
•
常见选项:
•
SO_ERROR
Return and clear pending socket error (
getsockopt
only).
•
SO_REUSEADDR
Reuse addresses in bind if *
val
is nonzero.
6、带外数据
•
out-of-band
数据,紧急数据,只能是单个字节
•
一个
socket
通信实际例子,包括客户端、服务端
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(void)
{
int s;
struct sockaddr_in sin;
if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("client:socket");
exit(1);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(1234);
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
if( connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0 )
{
perror("client:connect");
exit(1);
}
send(s, "a", 1, 0);
send(s, "1", 1, MSG_OOB); // 发送带外数据
send(s, "b", 1, 0);
close(s);
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int s, ns, fromlen;
void urg(int sig)
{
char b[64] = {0};
printf("sig catch %d\n", sig);
recv(ns, b, sizeof(b) - 1, MSG_OOB);
printf("OOB [%s]\n", b);
}
int main(void)
{
char b[64];
struct sockaddr_in sin, fsin;
signal(SIGURG, urg);
if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("server:socket");
exit(1);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(1234);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
if( bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0 )
{
perror("server:bind");
exit(1);
}
if( listen(s, 5) < 0 )
{
perror("server:listen");
exit(1);
}
fromlen = sizeof(fsin);
if( (ns = accept(s, (struct sockaddr *)&fsin, &fromlen)) < 0 )
{
perror("server:accept");
exit(1);
}
fcntl(ns, F_SETOWN, getpid());
memset(b, 0, sizeof(b));
recv(ns, b, sizeof(b) - 1, 0);
printf("[%s]\n", b);
memset(b, 0, sizeof(b));
recv(ns, b, sizeof(b) - 1, 0);
printf("[%s]\n", b);
close(ns);
close(s);
exit(0);
}