-
linux网络基础:
-
网络编程基础
-
网络地址:
struct sockaddr { u_short sa_family; char sa_data[14]; }
sa_family: 协议族,采用AF_XXX的形式,如:AF_INET(IP协议族)
sa_data: 14字节的特定协议地址
-
地址结构:
struct sockaddr_in { short int sin_family; //协议族 // unsigned short int sin_port; // 端口号 // struct in_addr sin_addr; // 协议特定地址 // unsigned char sin_zero[8]; // 填 0 }
typedef struct in_addr{ union{ struct{ unsigned char s_b1, s_b2, s_b3, s_b4; }S_un_b; struct{ unsigned short s_w1, s_w2, }S_un_w; unsigned long S_addr; }S_un; }IN_ADDR;
-
地址转换
**int inet_aton(const char cp, struct in_addr inp)
*char inet_ntoa(struct in_addr in)
inet_aton是将abcd形式的IP转换成32位的IP,存储在inp指针里面,inet_ntoa则与之相反。
-
Ip与主机名
在网络中标识一台主机可以用IP地址,也可以用主机名(获取主机名)
struct hostent *gethostbyname(const char *hostname)
struct hostent { char *h_name; //主机的正式名称 char *h_aliases;//主机的别名 int h_addrtype; //主机的地址类型 AF_INET int h_length; //主机的地址长度 char **h_addr_list;//主机的IP地址列表 } #define h_addr h_addr_list[0] //主机的第一个IP地址
-
网络编程常用函数
- socket:创建一个socket
- bind: 用于绑定IP地址和端口号到socket
- connect:用于与服务器建立连接
- listen: 设置服务器能处理的最大连接数
- accept: 用于等待来自客户端的socket连接请求
- send: 发送数据
- recv: 接收数据
-
TCP网络编程
-
步骤(服务器)
- 创建一个socket,用函数socket();
- 绑定IP地址、端口等信息到socket上,用函数bind()
- 设置最大允许连接数,用listen()
- 等待来自客户端的连接请求,用函数accept()
- 收发数据,用aend()和recv(),或者read()和write()
- 关闭网络连接
-
步骤(客户端)
-
创建一个socket,用函数socket();
-
设置要连接的服务器的IP地址和端口等属性
-
连接服务器,用函数connect()
-
收发数据,用函数send()和recv(),或者read()和write()
-
关闭网络连接
例子:tcp_cilen.c
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#define portnumber 3333
int main(int argc, char *argv[])
{
int sockfd;
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
if(argc != 2)
{
fprintf(stderr,"Usage: %s hostname \a\n",argv[0]);
exit(1);
}
if((host = gethostbyname(argv[1])) == NULL)
{
fprintf(stderr,"Gethostname error\a\n");
exit(1);
}
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
exit(1);
}
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portnumber);
server_addr.sin_addr = *((struct in_addr *)host -> h_addr);
if(connect(socket,(struct in_addr*)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
exit(1);
}
printf("please input char:\n");
fget(buffer,1024,stdin);
write(sockfd,buffer,strlen(buffer));
close(sockfd);
exit(0);
}
例子:tcp_server.c
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#define portnumber 3333
int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in cilent_addr;
int sin_size;
int nbytes;
char buffer[1024];
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
exit(1);
}
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portnumber);
server_addr.sin_addr.s_addr = htol(INADDR_ANY);
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"bind error : %s\n\a",strerror(errno));
exit(1);
}
if(listen(sockfd,5) == -1)
{
fprintf(stderr,"listen error %s\n\a",strerror(errno));
exit(1);
}
while(1)
{
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd,(struct sockaddr *)(&cilent_addr),&sin_size))==-1)
{
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
exit(1);
}
fprintf(stderr,"server get connection from %s\n\a",inet_ntoa(cilent_addr.sin_addr));
if((bbytes = read(new_fd,buffer,1024))==-1)
{
fprintf(stderr,"read error:%s\n",strerror(errno));
exit(1);
}
buffer[nbytes]='\0';
printf("server received %s\n",nuffer);
close(new_fd);
}
}
UDP网络编程
-
步骤(服务端)
- 创建一个socket,用函数socket()
- 绑定IP地址、端口等信息到socket上,用函数bind()
- 循环接收数据,用函数recvfrom()
- 关闭网络连接
-
步骤(客户端)
- 创建一个socket,用函数socket()
- 绑定IP地址、端口等信息到socket上,用函数bind()
- 设置对方的IP地址和端口等属性
- 发送数据,用函数sendto()
- 关闭网络连接,用close()
例子:udp_server.c
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define SERVER_PORT 8888
#define MAX_MSG_SIZE 1024
void udps_respon(int sockfd)
{
struct sockaddr_in addr;
int addrlen,n;
char msg[MAX_MSG_SIZE];
while(1)
{
//从网络上读取,并且发送到网络上
bzero(msg,sizeof(msg));
addrlen = sizeof(struct sockaddr);
n = recvfrom(sockfd,msg,MAX_MSG_SIZE,0,(struct sockaddr *)&addr,&addrlen);
msg[n]=0;
//显示服务端已经接收到的消息
fprintf(stdout,"Server have received %s",msg);
}
}
int main(void)
{
int sockfd;
struct sockaddr_in addr;
//服务器端开始建立socket描述符
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0)
{
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}
//服务器端填充 sockaddr结构
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
//捆绑sockfd描述符号
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) < 0)
{
fprintf(stderr,"Bind Error:%s\n",strerror(errno));
exit(1);
}
udps_respon(sockfd);//进行读写操作
close(sockfd);
}
例子:udp_cilent.c
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define SERVER_PORT 8888
#define MAX_MSG_SIZE 1024
void udpc_requ(int sockfd,const struct sockaddr_in *addr,int len)
{
char buffer[MAX_MSG_SIZE] ;
int n;
while(1){
printf("Please input char:\n");
fgets(buffer,MAX_MSG_SIZE,stdin);
sendto(sockfd,buffer,strlen(buffer),0,addr,len);
bzero(buffer,MAX_MSG_SIZE);
}
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in addr;
if(argc != 2)
{
fprintf(stderr,"Usage:%s server_ip \n",argv[0]);
exit(1);
}
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0)
{
fprintf(stderr,"socket error:%s \n",strerror(errno));
exit(1);
}
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
if(inet_aton(argv[1],&addr.sin_addr) < 0 )
{
fprintf(stderr,"IP error:%s \n",strerror(errno));
exit(1);
}
udpc_requ(sockfd,&addr, sizeof(struct sockaddr_in));//进行读写操作
close(sockfd);
}
循环服务器
-
UDP循环服务器
实现方法:
udp服务器每次从套接字上读取一个客户端的请求=》处理=》返还客户机。
socket(…);
bind(…);
while(1)
{
recvfrom(…);
process(…);
sendto(…);
}
实例:
-
TCP循环服务器
实现方法:
TCP的循环服务器在接收一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接。
socket(…);
bind(…);
listen(…);
while(1)
{
accept(…);
process(…);
close(…);
}
TCP循环服务器一次只能处理一个客户端的请求。如果由一个客户端占用了服务器不放时,其他的客户机都不能工作了,因此,TCP服务器一般很少用循环服务器模型。
并发服务器
-
TCP并发服务器
处理方式:每个客户机的请求并不是由服务器直接处理,而是由服务器创建一个子进程来处理。
socket(…);
bind(…);
listen(…);
while(1)
{
accept(…);
if(fork(…)==0){
process(…);
close(…);
exit(…);
}
close(…);
}
例子:tcp_server_fork.c
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#define portnumber 3333
int main(int argc, char **argv[])
{
int listen_fd,accept_fd;
struct sockaddr_in cilent_addr;
int n;
int nbytes;
if((listen_fd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
exit(1);
}
bzero(&cilent_addr,sizeof(struct sockaddr_in));
cilent_addr.sin_family = AF_INET;
cilent_addr.sin_port = htons(MY_INET);
cilent_addr.sin_addr.s_addr = htonl(INADDR_ANY);
n=1;
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(int));
if(bind(listen_fd,(struct sockaddr *)(&listen_addr),sizeof(struct listen_addr))<0)
{
fprintf(stderr,"bind error : %s\n\a",strerror(errno));
exit(1);
}
lisent(silent_fd,5);
while(1)
{
accept_fd = accept(listen_fd,NULL,NULL);
if((accept_fd<0)&&(errno == EINTR))
continue;
else if(accept_fd < 0)
{
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
exit(1);
}
if((n=foek())==0)
{
char buffer[1024];
//子进程处理客户端连接
if((nbytes = read(accept_fd,buffer,1024))== -1)
{
fprintf(stderr,"read error:%s\n",strerror(errno));
exit(1);
}
buffer[nbytes]='\0';
printf("server received %s\n",buffer);
close(listen_fd);
close(accept_fd);
exit(0);
}
else
close(accept_fd);
}
}