函数流程框图:
创建:
int socket(int domain,int type,int protocol);
domain——>协议域:
AF_INET————IPV4。
AF_INET6————IPV6。
AF_LOCAL————Unix域。
type——>类型:
SOCK_STREAM——流式套接字,TCP协议支持该套接字(提供面向连接,可靠的数据传输服务,数据按字节流,按顺序收发,保证在传输过程中无丢失,无冗余)。
SPCK_DGRAM———数据报套接字,UDP协议支持该套接字(提供面向无连接的服务,数据收发无序,不能保证数据的准确到达)。
SOCK_RAM————原始套接字,常用于检测新协议。允许对低于传输层的协议或物理网络直接访问。
protocol——>协议:
0————自动根据type匹配协议。
IPPROTO_TCP。
IPPROTO_UDP。
返回值:
>0时为socket描述符;-1为失败。
关闭:
int close(int fd);
int shutdown(int sockfd,int howto);
sockfd——socket套接字。
howto:
SHUT_RD———值为0;关闭连接的读。
SHUT_WR———值为1;关闭连接的写。
SHUT_RDWR——值为2;连接的读和写都关闭。
绑定:
int bind(int socket,const struct sockaddr* address,socklen_t address_len);
socket—————套接字描述符。
address—————地址和端口号。
address_len———address缓冲区的长度。
返回值——————0为成功;SOCKET_ERROR为失败。
监听:
int listen(int sockfd,int backlog);
socket—————监听的socket描述符。
backlog————排队的最大连接个数。
返回值—————0为成功;-1为失败。
连接:
int connect(int sockfd,const struct sockaddr* addr,socklen_t,addrlen);
sockfd————客户端的socket描述符。
addr—————服务器的socket地址。
addrlen————服务器的socket地址的长度。
返回值—————0为成功l-1为失败。
接受:
int accept(int sockfd,struct socketaddr* addr,socklen_t* addrlen);
sockfd————服务器的socket描述符,或,监听socket描述符。
addr—————客户端的socket地址。
addrlen————客户端的socket地址长度。
返回值————非-1为连接描述符;-1为失败。
发送:
ssize_t write(int fd,const void* buf,size_t len);
fd————文件描述符。
buf————写入的数据。
len————写入数据长度。
返回值———>0为实际所写的字节数;<0出错。
ssize_t send(int sockfd,const void* buf,size_t len,int flags);
flags——通常为0。
返回值及其他——同上。
ssize_t sendto(int sockdf,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);
dest_addr———目标socket地址。
addrlen————目标socket地址长度。
返回值及其他——同上。
接收:
ssize_t read(int fd,void* buf,size_t len);
buf————读取文件。
返回值——0为读到文件的结束;>0实际所读到的字节数;<0出错。
ssize_t recv(int sockfd,void* buf,size_t len,int flags);
flags——————通常为0。
返回值及其他——同上。
ssize_t recvfrom(int sockdf,void* buf,size_t len,int flags,const struct sockaddr* src_addr,socklen_t addrlen);
结构体:
struct sockaddr:
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
struct sockaddr_in:
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr:
struct in_addr {
in_addr_t s_addr;
};
in_addr_t:
typedef unsigned int in_addr_t;
struct sockaddr_in6(IPV6):
struct sockaddr_in6{
//IPv6 为固定的24 字节长度
uint8_t sin6_len;
//地址簇类型,为AF_INET6
sa_family_t sin6_family;
//16 位端口号,网络字节序
in_port_t sin6_port;
//32 位流标签
uint32_t sin6_flowinfo;
//128 位IP 地址
struct in6_addr sin6_addr;
}
特殊地址设置:
通配地址(0.0.0.0):
in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
in6_addr.sin6_addr = in6addr_any;
回环地址(127.0.0.1):
in_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
in6_addr.sin6_addr = in6addr_loopback;
广播地址:
in_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
代码:
tcp_cliect:
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(4 != argc){
printf("usage:%s <ip> <#port> <message>\n",argv[0]);
return 1;
}
int connfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == connfd){
perror("socket err");
return 1;
}
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]));
if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
perror("connect err");
return 1;
}
show_info(connfd);
write(connfd,argv[3],strlen(argv[3])+1);
printf("client send:%s\n",argv[3]);
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
if(-1 == read(connfd,buf,BUFSIZ)){
perror("read err");
return 1;
}
printf("client recv:%s\n",buf);
close(connfd);
}
tcp_server:
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port>\n",argv[0]);
return 1;
}
int listenfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == listenfd){
perror("listenfd open err");
return 1;
}
printf("socket create OK\n");
int flag = 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr(argv[1]);
local_addr.sin_port = htons(atoi(argv[2]));
if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
perror("bind err");
return 1;
}
printf("bind OK\n");
if(-1 == listen(listenfd,10)){
perror("listen err");
return 1;
}
printf("listen OK\n");
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
socklen_t remote_addr_len = sizeof(remote_addr);
int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
if(-1 == connfd){
perror("accept err");
return 1;
}
show_info(connfd);
printf("accept %s:%d\n",inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port));
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
if(-1 == read(connfd,buf,BUFSIZ-1)){
perror("read err");
return 1;
}
printf("server recv:%s\n",buf);
if(-1 == write(connfd,buf,strlen(buf)+1)){
perror("write err");
return 1;
}
printf("server send:%s\n",buf);
close(connfd);
close(listenfd);
}