套接字的域
套接字的类型
协议类型
头文件
#include
以太网中的字节序是大端的,因此相关的以太网的数据在小端机器上需要使用相关接口转换为以太网字节序。常用转换工具函数:
- //4字节整形变量主机字节序的转换为网络字节序
- uint32_t htonl(uint32_t hostint32);
- //2字节整形变量主机字节序的转换为网络字节序
- uint16_t htons(uint15_t hostint16);
- //和上面相反
- uint32_t ntohl(uint32_t netint32);
- //和上面相反
- uint32_t ntohl(uint32_t netint32);
常用接口(具体使用man 2 xxx 命令查看具体说明)
- //创建套接字
- int socket(int domain,int type,int protocol);
- //将一个套接字和指定地址和端点关联起来
- int bind(int sockfd,const struct sockaddr * addr,socklen_t addrlen);
- //开始监听这个套接字
- int listen(int socket, int backlog);
- //向指定socket发起连接请求
- int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- //接收监听到的一个socket连接请求
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- //通过socket 发送数据,地址是socket默认
- ssize_t send(int sockfd, const void *buf, size_t len, int flags);
- //通过socket 接收数据,地址为socket 默认
- ssize_t recv(int sockfd, void *buf, size_t len, int flags);
- //通过socket 发送数据,地址是由参数指定
- ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
- //通过socket 接收数据,地址由参数指定
- ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
- //常用在unix 域下的进程通讯,发送数据
- ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
- //常用在unix 域下的进程通讯,接收数据
- ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
- //获取当前socket信息
- int getsockname((int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- //获取原端socket信息(建立连接之后)
- int getpeername((int sockfd, const struct sockaddr *addr, socklen_t addrlen);
关闭套接字
套接字关闭可以像关闭一个文件的描述符一样调用close()接口来关闭socket接口,除此之外还可以使用shutdown接口进行更加细致的关闭操作:
- sockfd :sock描述符
- how :SHUT_RDWR 读写两端都关闭
- : SHUT_WR 关闭写端
- : SHUT_RD 关闭读端
- 返回值 :成功返回0 失败返回-1
- int shutdown(int sockfd,int how);
相关结构体
- //描述网络信息
- struct sockaddr_in {
- s_add.sin_family = AF_INET;
- s_add.sin_port = htons(1040);
- s_add.sin_addr.s_addr = inet_addr("127.0.0.1");
- };
TCP服务端配置过程
- //建立 IPv4域下的字节流服务的TCP协议的socket
- int sockfd_s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- //将这个socket个特定地址何端口关联起来
- bind(sockfd_s,(struct sockaddr*)&s_add,sizeof(struct sockaddr_in))
- //开始监听
- listen(sockfd_s,1)
- //接受任意连接请求,返回可以用来数据传输的socket描述符
- accept(sockfd_s,NULL,NULL);
TCP客户端配置过程
- //建立 IPv4域下的字节流服务的TCP协议的socket
- int sockfd_s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- //向制定地址和端口发起链接请求
- connect(sockfd_c,(struct sockaddr*)&c_add,sizeof(c_add))
示例代码
见文末
连接信息获取
获取本地套接字信息
获取远端套接字信息(连接后)
套接字选项
设置选项
int setsockopr(int sockfd,int level,int option,void *val,socklen_t len);
获取选项
int setsockopr(int sockfd,int level,int option,void *val);
带外数据
是一些通讯协议支持的可选功能,与普通数据相比其具有更高的优先级被传输。目前TCP的支持带外数据传输的,仅支持一个字节的紧急数据。有些实现TCP的带外数据还可以产生SIGURG信号。还可以通过下面的接口判断是否有紧急数据,当有紧急数据时,返回1。
iny sockatmark(int sockfd);
异步socket和非阻塞socket
基本上socket的异步IO和阻塞和非阻塞的处理和普通的文件基本相同,但是有一些区别的是,但是目前还没有完整的标准,视具体平台的实现情况。
- int main(int argc,int *argv)
- {
- char *name,i;
- struct hostent* host;
- size_t len = sysconf(_SC_HOST_NAME_MAX);
- if(len>0){
- name = malloc(len+1);
- }else{
- name = malloc(1024);
- len = 1024;
- }
- printf("Buff size%ld\n",stdout->_IO_buf_end-stdout->_IO_buf_base);
- if(gethostname(name,len)<0){
- printf("gethostname error!\n");
- }
- host = gethostbyname(name);
- if(*host->h_aliases){
- printf("%s\n%s\n%s\n%d\n",
- host->h_name,//host name
- *host->h_aliases, //host_name aliases
- (host->h_addrtype==AF_INET?"IP_V4":"IP_V6"),
- host->h_length);
- }else{
- printf("%s\n%s\n%d\n",
- host->h_name,
- (host->h_addrtype==AF_INET?"IP_V4":"IP_V6"),
- host->h_length);
- }
- for(i=0;host->h_addr_list[i] != NULL;i++){
- printf("%s\n",inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
- }
- printf("befor the fork call\n\n");
- int pid = fork();
- if(pid){
- int status,temp=1;
- int sockfd_s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(sockfd_s<0){
- goto fail;
- }
- if(setsockopt(sockfd_s,SOL_SOCKET,SO_REUSEADDR,&temp,sizeof(int)) < 0)
- {
- perror("setsockopt");
- }
- struct sockaddr_in s_add;
- s_add.sin_family = AF_INET;
- s_add.sin_port = htons(1040);
- s_add.sin_addr.s_addr = inet_addr("127.0.0.1");
- // inet_pton(AF_INET,"127.0.0.1",&s_add.sin_addr);
- if(bind(sockfd_s,(struct sockaddr*)&s_add,sizeof(s_add))<0){
- printf("1\n");
- goto fail;
- }
- if(listen(sockfd_s,1)<0){
- goto fail;
- }
- int c_fd = accept(sockfd_s,NULL,NULL);
- if(c_fd < 0){
- goto fail;
- }
- int len=sizeof(s_add);
- if(getpeername(c_fd,(struct sockaddr*)&s_add,&len)<0){
- printf("2\n");
- goto fail;
- }
- printf("server:\n%s\n%d\n",inet_ntoa(s_add.sin_addr),ntohs(s_add.sin_port));
- if(c_fd){
- while(1){
- char buf[64];
- recv(c_fd,buf,64,0);
- printf("%s\n",buf);
- sleep(1);
- }
- }
- fail:
- close(sockfd_s);
- perror(strerror(errno));
- kill(pid,9);
- waitpid(pid,&status,0);
- printf("server end\n");
- return 0;
- }else if(!pid){
- sleep(3);
- int sockfd_c = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- if(sockfd_c<0){
- goto fail_c;
- }
- struct sockaddr_in c_add;
- c_add.sin_family = AF_INET;
- c_add.sin_port = htons(1040);
- c_add.sin_addr.s_addr = inet_addr("127.0.0.1");
- // inet_pton(AF_INET,"127.0.0.1",&c_add.sin_addr);
- if(connect(sockfd_c,(struct sockaddr*)&c_add,sizeof(c_add))){
- goto fail_c;
- }
- struct sockaddr_in d_add;
- int len=sizeof(d_add);
-
- if(getpeername(sockfd_c,(struct sockaddr*)&d_add,&len)<0){
- goto fail_c;
- }
- printf("cliens\n%s\n%d\n",inet_ntoa(d_add.sin_addr),ntohs(d_add.sin_port));
- while(1)
- {
- send(sockfd_c,"hello word!\n",strlen("hello word!\n"),0);
- sleep(1);
- }
- fail_c:
- close(sockfd_c);
- perror(strerror(errno));
- _exit(0);
- }
- return 0;
- }