通过socket编程大致对网路编程的脉络有个大致的了解,如果有不太懂的地方,
咱们可以到网络上查找手册
创建socket
int socket(int domain, int type, int protocol);
1. domain 指定使用何种的地址类型
协议 说明
PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX 进程通信协议
PF_INET/AF_INET Ipv4 网络协议
PF_INET6/AF_INET6 Ipv6 网络协议
PF_IPX/AF_IPX IPX-Novell 协议
PF_NETLINK/AF_NETLINK 核心用户接口装置
PF_X25/AF_X25 ITU-T X. 25/ISO-8208 协议
PF_AX25/AF_AX25 业余无线AX. 25 协议
PF_ATMPVC/AF_ATMPVC 存取原始 ATM PVCs
PF_APPLETALK/AF_APPLETALK appletalk (DDP)协议
PF_PACKET/AF_PACKET 初级封包接口
PF_INET/AF_INET Ipv4 网络协议
PF_INET/AF_INET Ipv4 网络协议
2. type的类别。见表:
类型 说明
SOCK_STREAM 提供双向连续且可信赖的数据流, 即TCP
SOCK_DGRAM 使用不连续不可信赖的数据包连接
SOCK_SEQPACKET 提供连续可信赖的数据包连接
SOCK_RAW 提供原始网络协议存取
SOCK_RDM 提供可信赖的数据包连接
SOCK_PACKET 提供和网络驱动程序直接通信
3. protocol 用来指定socket 所使用的传输协议编号,通常为0
成功返回0 失败返回-1
命名socket
int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
0 正确
常用的错误:EACCES,EADDRINUSE
监听socket–创建一个监听队列
int liseten(int socketfd,int backlog)
接受连接
accet(int socketfd,struct sockaddr * my_addr, int addrlen)
从队列中接受一个连接
发起连接
connect(int socketfd,struct sockaddr * my_addr, int addrlen)
关闭连接
close(int fd)
tcp数据读写
recv(int fd,void*buf,size_t len,int flags)
send(int fd,const void *buf,size_t len,int flags)
flag 有一些特别的参数
持续监听对方的回应
不经过路由表
对socket非阻塞
发送紧急数据
不接受sig信号等等
udp数据读写
recvfrom(int fd,void*buf,size_t len,int flags,struct sockaddr * my_addr, int addrlen)
sendto(int fd,const void*buf,size_t len,int flags,struct sockaddr * my_addr, int addrlen)
通用数据读写
recvmsg(int fd,struct msghdr*msg,int flags);
sendmsg(int fd,struct msghdr*msg,int flags);
struct msghdr
{
void* msg_name;
socklen_t msg_namelen;
struct iovec*msg_iov;
int msg_iovlen;
void* msg_control;
socklen_t msg_controllen;
int msg_flags;
};
struct iovec
{
void *iov_base;
size_t iov_len;
};
带外标记判断
int sockatmark(int sockfd);
地址信息函数
int getsockname(int socketfd,struct sockaddr * my_addr, int addrlen);//本端的地址信息
int getpeername(int socketfd,struct sockaddr * my_addr, int addrlen);//远端的地址信息
socket选项
获取socket选项
getsockopt(int socketfd,int opt_name,void*option_value,socket_t restrict option_len)
设置socket选项
getsockopt(int socketfd,int opt_name,void*option_value,socket_t restrict option_len)
这个可以查看手册。
选项名称 说明 数据类型
========================================================================
SOL_SOCKET
------------------------------------------------------------------------
SO_BROADCAST 允许发送广播数据 int
SO_DEBUG 允许调试 int
SO_DONTROUTE 不查找路由 int
SO_ERROR 获得套接字错误 int
SO_KEEPALIVE 保持连接 int
SO_LINGER 延迟关闭连接 struct linger
SO_OOBINLINE 带外数据放入正常数据流 int
SO_RCVBUF 接收缓冲区大小 int
SO_SNDBUF 发送缓冲区大小 int
SO_RCVLOWAT 接收缓冲区下限 int
SO_SNDLOWAT 发送缓冲区下限 int
SO_RCVTIMEO 接收超时 struct timeval
SO_SNDTIMEO 发送超时 struct timeval
SO_REUSERADDR 允许重用本地地址和端口 int
SO_TYPE 获得套接字类型 int
SO_BSDCOMPAT 与BSD系统兼容 int
========================================================================
IPPROTO_IP
------------------------------------------------------------------------
IP_HDRINCL 在数据包中包含IP首部 int
IP_OPTINOS IP首部选项 int
IP_TOS 服务类型
IP_TTL 生存时间 int
========================================================================
IPPRO_TCP
------------------------------------------------------------------------
TCP_MAXSEG TCP最大数据段的大小 int
TCP_NODELAY 不使用Nagle算法 int
========================================================================
获取主机信息
根据名字获取主机信息
struct hostent* gethostbyname(const char *name)
根据ip获取主机信息
struct hostent* gethostbyaddr(const void *addr,size_t len,int type)
struct hostent
{
char *h_name;//主机名
char** h_aliases;//主机别名,可能有多个
int h_addrtype;//地址类型
int h_length;// 地址长度
char ** h_addr_list//按照网络字节序列列出idp地址列表
}
获取服务信息
//根据 名字,端口号获取服务信息
struct servent*getservbyname(const char *name,const char *proto);
//根据服务类型,端口号获取服务信息
struct servent*getservbyport(int port,const char *proto);
struct servent{
char *h_name;//主机名
char** h_aliases;//主机别名,可能有多个
int s_port;//端口号
char *s_proto;//服务类型,tcp或者upd等
}
通过主机名获取ip地址
int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );
通过socket地址获取主机名
int getnameinfo (const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags) ;
tcp编程的例子server
//
// main.cpp
// linux_socket_api
//
// Created by bikang on 16/11/2.
// Copyright (c) 2016年 bikang. All rights reserved.
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//using namespace std;
#define BUFFER_SIZE 1024
void tsocket(int argc, const char * argv[]);
int main(int argc, const char * argv[]) {
tsocket(argc,argv);
return 0;
}
void tsocket(int argc, const char * argv[]){
if(argc < 3){
exit(-1);
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int backlog = atoi(argv[3]);
std::cout << "ip=" << ip << " port="<" backlog=" << backlog << std::endl;
int fd;
int check_ret;
fd = socket(PF_INET,SOCK_STREAM , 0);
assert(fd >= 0);
struct sockaddr_in address;
bzero(&address,sizeof(address));
//转换成网络地址
address.sin_port = htons(port);
address.sin_family = AF_INET;
//地址转换
inet_pton(AF_INET, ip, &address.sin_addr);
//设置socket buffer大小
int recvbuf = 4096;
int len = sizeof( recvbuf );
setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &recvbuf, sizeof( recvbuf ) );
getsockopt( fd, SOL_SOCKET, SO_RCVBUF, &recvbuf, ( socklen_t* )&len );
printf( "the receive buffer size after settting is %d\n", recvbuf );
//绑定ip和端口
check_ret = bind(fd,(struct sockaddr*)&address,sizeof(address));
assert(check_ret >= 0);
//创建监听队列,用来存放待处理的客户连接
check_ret = listen(fd, backlog);
assert(check_ret >= 0);
struct sockaddr_in addressClient;
socklen_t clientLen = sizeof(addressClient);
//接受连接,阻塞函数
int connfd = accept(fd, (struct sockaddr*)&addressClient, &clientLen);
if(connfd < 0){
std::cout << "accept error";
}else{
//打印客户端信息
char showData[INET_ADDRSTRLEN];
std::cout <":" <std::endl;
//接受数据
const int BUF_LEN = 1024;
char sockBuf[BUF_LEN];
size_t ret;
memset(sockBuf, '\0', BUF_LEN);
ret = recv(connfd, sockBuf, BUF_LEN-1, 0);
printf("ret=%ld,msg=%s\n",ret,sockBuf);
memset(sockBuf, '\0', BUF_LEN);
ret = recv(connfd, sockBuf, BUF_LEN-1, MSG_OOB);
printf("ret=%ld,msg=%s\n",ret,sockBuf);
memset(sockBuf, '\0', BUF_LEN);
ret = recv(connfd, sockBuf, BUF_LEN-1, 0);
printf("ret=%ld,msg=%s\n",ret,sockBuf);
//获取本地socket信息
struct sockaddr_in tmpAddress;
clientLen = sizeof(tmpAddress);
getsockname(fd, (struct sockaddr*)&tmpAddress, &clientLen);
std::cout <":" <std::endl;
//获取远端socket信息
getpeername(connfd,(struct sockaddr*)&tmpAddress, &clientLen );
std::cout <":" <std::endl;
close(connfd);
}
close(fd);
}
tcp编程的例子client
//
// main.cpp
// linux_socket_api_client
//
// Created by bikang on 16/11/2.
// Copyright (c) 2016年 bikang. All rights reserved.
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void tserver(int argc, const char * argv[]);
int main(int argc, const char * argv[]) {
tserver(argc,argv);
return 0;
}
void tserver(int argc, const char * argv[]){
std::cout << "t server" << std::endl;
if(argc < 3){
exit(-1);
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int backlog = atoi(argv[3]);
std::cout << "ip=" << ip << " port="<" backlog=" << backlog << std::endl;
int fd;
int check_ret;
fd = socket(PF_INET,SOCK_STREAM , 0);
assert(fd >= 0);
int sendbuf = 4096;
int len = sizeof( sendbuf );
setsockopt( fd, SOL_SOCKET, SO_SNDBUF, &sendbuf, sizeof( sendbuf ) );
getsockopt( fd, SOL_SOCKET, SO_SNDBUF, &sendbuf, ( socklen_t* )&len );
printf( "the send buffer size after settting is %d\n", sendbuf );
struct sockaddr_in address;
bzero(&address,sizeof(address));
//转换成网络地址
address.sin_port = htons(port);
address.sin_family = AF_INET;
//地址转换
inet_pton(AF_INET, ip, &address.sin_addr);
check_ret = connect(fd, (struct sockaddr*) &address, sizeof(address));
assert(check_ret >= 0);
//发送数据
const char* oob_data = "abc";
const char* normal_data = "my boy!";
send(fd, normal_data, strlen(normal_data), 0);
send(fd, oob_data, strlen(oob_data), MSG_OOB);
send(fd, normal_data, strlen(normal_data), 0);
close(fd);
}
udp编程的例子server
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//using namespace std;
#define BUFFER_SIZE 1024
void tsocket(int argc, const char * argv[]);
int main(int argc, const char * argv[]) {
tsocket(argc,argv);
return 0;
}
void tsocket(int argc, const char * argv[]){
if(argc < 3){
exit(-1);
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int backlog = atoi(argv[3]);
std::cout << "ip=" << ip << " port="<" backlog=" << backlog << std::endl;
int fd;
int check_ret;
fd = socket(PF_INET,SOCK_DGRAM , 0);
assert(fd >= 0);
struct sockaddr_in address;
bzero(&address,sizeof(address));
//转换成网络地址
address.sin_port = htons(port);
address.sin_family = AF_INET;
//地址转换
inet_pton(AF_INET, ip, &address.sin_addr);
//绑定ip和端口
check_ret = bind(fd,(struct sockaddr*)&address,sizeof(address));
assert(check_ret >= 0);
while(1){
char buffer[BUFFER_SIZE];
struct sockaddr_in addressClient;
socklen_t clientLen = sizeof(addressClient);
memset(buffer, '\0', BUFFER_SIZE);
//获取信息
if(recvfrom(fd, buffer, BUFFER_SIZE-1,0,(struct sockaddr*)&addressClient, &clientLen) == -1)
{
perror("Receive Data Failed:");
exit(1);
}
printf("buffer=%s\n", buffer);
}
close(fd);
}
udp编程的例子client
//
// main.cpp
// linux_socket_api_client
//
// Created by bikang on 16/11/2.
// Copyright (c) 2016年 bikang. All rights reserved.
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void tserver(int argc, const char * argv[]);
int main(int argc, const char * argv[]) {
tserver(argc,argv);
return 0;
}
void tserver(int argc, const char * argv[]){
std::cout << "t server" << std::endl;
if(argc < 3){
exit(-1);
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int backlog = atoi(argv[3]);
std::cout << "ip=" << ip << " port="<" backlog=" << backlog << std::endl;
int fd;
int check_ret;
fd = socket(PF_INET,SOCK_DGRAM , 0);
assert(fd >= 0);
struct sockaddr_in address;
bzero(&address,sizeof(address));
//转换成网络地址
address.sin_port = htons(port);
address.sin_family = AF_INET;
//地址转换
inet_pton(AF_INET, ip, &address.sin_addr);
//发送数据
const char* normal_data = "my boy!";
if(sendto(fd, normal_data, strlen(normal_data),0,(struct sockaddr*)&address,sizeof(address)) < 0)
{
perror("Send File Name Failed:");
exit(1);
}
close(fd);
}