标签:add bind back 相关 clu 设置 传输 协议 one
前言:整理下Linux下socket编程相关的一下API和知识点
流式套接字处理流程
数据报套接字处理流程
字节序:字节序有大端小端之分,不同的处理架构在存储一个多字节数字时,若低内存地址存储该数字高位部分,则叫大端字节序,反之则叫小端字节序。因此,为了统一网络中传输的数据的字节序,有了网络序,发送到网络中的数据必须采用网络序。
主机字节序转网络字节序的函数
#include <arpa/inet.h>
uint32_t htonl(uint32_t t) //h代表host主机字节序,n代表net网络字节序,l代表long类型,s代表short类型 //将主机字节序转成网络字节序
uint16_t htons(uint16_t t)
uint32_t ntohl(uint32_t t) //将网络字节序转成主机字节序
uint16_t ntohs(uint16_t t)
地址格式:连接主机的地址的一个抽象
struct sockaddr{
unsigned short sa_family ; //地址协议族,一般为AF_INET,代表IPv4协议
char sa_data[14];
};
该结构不好用,所以有另一个结构
struct sockaddr_in{
short int sin_family ; //地址协议族,一般为AF_INET,代表IPv4协议
unsigned short int sin_port; //端口号,为0表示随机选一个端口
struct in_addr sin_addr; //IP地址 INADDR_ANY 表示使用自己的IP地址
unsigned char sin_zero[8]; //添0,为了和sockaddr一样大
};
struct in_addr{
unsigned long s_addr;
};
IP地址转换:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp); //将ip地址字符串转换为相应的类型,转换后已是网络序,出错返回-1,即255.255.255.255
char * inet_nota(struct in_addr);//将IP地址转换为字符串
套接字类型:SOCK_STREAM流式套接字采用tcp协议,可靠的,面向连接的字节流服务。SOCK_DGRAM数据报套接字,面向无连接的,不可靠的数据报服务。还有一个原始套接字,用于协议开发,比较底层。
socket函数
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain,int type,int protocol); //domain 协议族,type套接字类型,protocol一般为0,返回一个套接子描述符,相当于文件描述符出错返回-1
bind函数:将套接字描述符,绑定到地址上
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd,struct sockaddr *my_addr,int addrlen); //sockfd套接字描述符,addrlen为sizeof(struct sockaddr)
connect函数
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd,struct sockaddr *serv_addr,int addrlen);
listen函数
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd,int backlog); //backlog表示未经过处理的连接请求队列可以容纳的最大数目,一般设为5-10之间的数
accept函数
#include <sys/socket.h>
int accept(int sockfd,void *addr,int *addrlen);//sockfd正在listen的一个套接字描述符,addr指向struct sockaddr类型的指针,用来存储远程连接端点的地址,addrlen地址的长度,返回远程端点地址的套接字描述符。
接受消息,发送消息的函数
#include <sys/types.h>
#include <sys/socket.h>
int send(int sockfd,const void *msg,int len,int flags);..sockfd远程连接的套接字描述符,msg指向一个消息结构体的指针,len消息的字节个数,flags一般为0,返回发送的数据的长度。send函数有大小限制,如果发送的数据过多,可以分多次发送。
int recv(int sockfd,void *buf,int len,unsigned flags);//返回buf的长度,
以上2个函数用于流式套接字
int sendto(int sockfd,const void *msg,int len,unsigned int flags,const struct sockaddr *to,int tolen);
//sockfd远程主机的套接字,sockaddr 远程主机的地址
int recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,int *fromlen);
这2个函数用数据报套接字
close和shutdown函数
close(sockfd) //关闭套接字,套接字将不允许进行读写操作
#include <sys/socket.h>
int shutdown(int sockfd,int how)//how:0表示不允许接受数据,1,表示不允许发送数据,2和colse一样。
//tcpserver.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <sys/wait.h> #define PORT 4008 #define BACKLOG 10 #define BUFSIZE 4096 void process(char * cmd); int main(int argc,char* argv[]) { int lsockfd,rsockfd; struct sockaddr_in lsocket,rsocket; if((lsockfd=socket(AF_INET,SOCK_STREAM,0))<0) //服务器端套接字 { perror("socket"); exit(1); } lsocket.sin_family=AF_INET; //设置服务器端地址 lsocket.sin_port=htons(PORT); lsocket.sin_addr.s_addr=INADDR_ANY; bzero(&(lsocket.sin_zero),8); if(bind(lsockfd,(struct sockaddr *)&lsocket,sizeof(struct sockaddr))<0) //将服务器端地址与套接字绑定 { perror("bind"); exit(1); } if(listen(lsockfd,BACKLOG)<0) //监听服务器端套接字,若有客户端connect,则将其加入监听队列 { perror("listen"); exit(1); } int sin_size=sizeof(struct sockaddr); int count=0; while(1) { printf("wait for connecting!\n"); if((rsockfd=accept(lsockfd,(struct sockaddr *)&rsocket,&sin_size))<0) //处理客户端请求 { perror("accept"); continue; } count++; printf("someone connect!,current people %d\n",count); if(!fork()) //为么一个客户端建立一个处理子进程,用来收发数据 { char str[BUFSIZE]; int numbytes=0; while(1) { if((numbytes=recv(rsockfd,str,BUFSIZE-1,0))<0) { perror("recv"); break; } str[numbytes]=‘\0‘; if(strcmp(str,"quit")==0) { printf("client quit!\n"); break; } printf("receive a message: %s\n",str); if(send(rsockfd,str,strlen(str),0)<0) { perror("send"); break; } } close(rsockfd); exit(0); } while(waitpid(-1,NULL,WNOHANG)>0) //此处不会阻塞若第三个参数为WUNTRACED则会阻塞,若有客户端子进程退出,则输出相关语句 { count--; printf("someone quit!,current people have %d\n",count); } } return 0; }
//tcpclient.c gcc tcpclient.c -o tcpclient 运行tcpclient 127.0.0.1 //输入quit退出
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 4008 #define MAXDATASIZE 4096 #define BUFSIZE 4096 int main(int argc,char *argv[]) { int rsockfd; struct sockaddr_in rsocket; if(argc!=2) { fprintf(stderr,"usage:client hostname\n"); exit(1); } if((rsockfd=socket(AF_INET,SOCK_STREAM,0))<0) //创建一个服务器端套接字 { perror("sock"); exit(1); } rsocket.sin_family=AF_INET; //设置服务器端地址 rsocket.sin_port=htons(PORT); rsocket.sin_addr.s_addr=inet_addr(argv[1]); // if(inet_pton(AF_INET,argv[1],&rsocket.sin_addr)<0) // { // perror("inet_pton"); // exit(1); // } // rsocket.sin_addr=*(struct in_addr*)he->h_addr; bzero(&(rsocket.sin_zero),8); if(connect(rsockfd,(struct sockaddr*)&rsocket,sizeof(struct sockaddr))<0) //连接服务器 { perror("connect"); exit(1); } char sstr[BUFSIZE]; char rstr[BUFSIZE]; while(1) //收发数据,输入quit退出 { printf("%15s","command is: "); int len=0; fgets(sstr,BUFSIZE,stdin); sstr[strlen(sstr)-1]=0; if(send(rsockfd,sstr,strlen(sstr),0)<0) { perror("send"); continue; } if(strcmp(sstr,"quit")==0) break; int numbytes=0; if((numbytes=recv(rsockfd,rstr,BUFSIZE-1,0))<0) { perror("recv"); continue; } rstr[numbytes]=‘\0‘; printf("%15s%s\n","result is: ",rstr); } close(rsockfd); return 0; }
标签:add bind back 相关 clu 设置 传输 协议 one
原文地址:http://www.cnblogs.com/CodingUniversal/p/7424666.html