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、地址格式
•structin_addr {
• in_addr_t
s_addr;}
/* IPv4 address */
•structsockaddr_in {
• sa_family_t
sin_family;
/* address family */
• in_port_t
sin_port;
/* port number */
• structin_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);
}
本文详细介绍了Socket编程的基础知识,包括socket描述符的创建、寻址、连接建立、数据传输及socket选项设置等内容,并通过一个简单的客户端和服务端通信示例来演示带外数据的使用。

1474

被折叠的 条评论
为什么被折叠?



