Linux网络编程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux网络编程相关的知识,希望对你有一定的参考价值。

前言:整理下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地址转换为字符串

 

int inet_pton(int af,const char* src,void* dst); 

将ip地址字符串转换为相应的类型,转换后已是网络序,使用方式例子:inet_pton(AF_INET,ip,&address.sin_addr),成功返回1,失败返回0,并置errno

 

const char* inet_ntop(int af,cosnt void* src,char* dst,socklen_t cnt);

将ip转换为字符串,cnt可以是INET_ADDRSTRLEN(16),INET6_ADDRSTRLEN(46);失败返回NULL。

 

 

套接字类型: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; }

 

以上是关于Linux网络编程的主要内容,如果未能解决你的问题,请参考以下文章

[linux][c/c++]代码片段01

VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装

VSCode自定义代码片段14——Vue的axios网络请求封装