网络(三) --网络编程基础
这次我们从一个聊天程序的服务器和客户端来介绍网络编程的一些基础函数,以及该这么使用它们。
先上一张图来简单描述一下它们的关系
函数介绍
1.套接字,啥是套接字,套接字是计算机底层的一种通信方式,可以实现不同主机之间的通信,看这个东西就是网络通信的基础了。它也是一种封装接口,我们可以很简单的使用它就实现复杂的通信。
int sock = socket(AF_INET,SOCK_STREAM,0);
第一个参数是协议族,协议族决定了socket的地址类型,在通信中必须采用对应的地址,AF_INET决定了要用IPv4地址(32位)和16位端口的组合
第二个参数是socket的类型,SOCK_STREAM表示提供面向连接的稳定数据传输,即TCP协议,SOCK_DGRAM表示使用不连续不稳定的数据包连接,即UDP协议
第三个参数是协议,常用的协议有IPPROTO_TCP,IPPTOTO_UDP,IPPROTO_SCTP,IPPROTO_TIRC等,它们分别对应TCP,UDP,SCTP,TIPC传输协议,当参数是0时,会自动socket类型对应的默认协议
2.bind
套接字创建完成之后会存在协议族空间中,但是没有一个具体的地址,这是就需要bind来给套接字绑定一个具体的地址
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
第一个参数就是我们创建的套接字
第二个参数就是给套接字绑定的地址空间
struct sockaddr_in{
sa_family_t sin_family; //协议族
in_port_t sin_port; //端口
struct in_addr sin_addr;//网络地址,由主机地址转换而来(IP地址是主机地址)
}
struct in_addr{
uint32_t s_addr; //网络地址字节序
}
3.listen
服务器端bind之后就需要监听端口,需要调用listen
int listen(int sockfd,int backlog);
第一个参数是要监听的套接字的描述符
第二个参数是socket可以排队的最大连接数
4.connect
客户端在建立套接字之后就可以请求连接服务器了
int connect(int socket,const struct sockaddr *addr,socklen_t addrlen);
第一个参数是客户端套接字描述符
第二个参数是服务器端套接字的地址
第三个参数是服务器套接字的长度
5.accept
服务器监听到客户端的请求时,就调用accept来接收请求,这样就可以建立连接了。
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
第一个参数是服务器端的套接字
第二个参数是客户端套接字的地址
第三个参数是客户端套接字的长度
6.read/write
客户端和服务器建立连接之后,就可以向操纵文件一样来操纵套接字
read()/write
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendfrom()
7.close
不再需要使用套接字之后就可以将它们关闭,这个时候客户端和服务器就会断开连接
事例程序
/***** server.c *****/
#include <sys/time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/select.h>
#define LISTEN_NUM 5
int main(int argc,char **argv){
struct sockaddr_in nowAddr,newAddr;
int nowfd,newfd;
char buff[1024];
bzero(&nowAddr,sizeof(nowAddr));
nowAddr.sin_family = AF_INET;
nowAddr.sin_port = htons(6666);
nowAddr.sin_addr.s_addr = INADDR_ANY;
if((nowfd = socket(AF_INET,SOCK_STREAM,0)) == -1){
printf("socket\n");
return 0;
}
if( bind(nowfd,(struct sockaddr*)&nowAddr,sizeof(struct sockaddr)) == -1){
printf("bind\n");
return 0;
}
if( listen(nowfd,LISTEN_NUM) == -1){
printf("listen\n");
return 0;
}
printf("wait to connect......\n");
int size = sizeof(struct sockaddr);
bzero(&newAddr,sizeof(newAddr));
newfd = accept(nowfd,(struct sockaddr*)&newAddr,(socklen_t*)&size);
pid_t pid = fork();
if(pid == 0){
while(1){
bzero(buff,sizeof(buff));
int ret = read(newfd,buff,sizeof(buff));
if(ret > 0){
if(!strncasecmp(buff,"quit",4)){
printf("I will quit read!\n");
break;
}
printf("I have receive: %s\n",buff);
}
}
}else{
while(1){
bzero(buff,sizeof(buff));
fgets(buff,sizeof(buff),stdin);
if(!strncasecmp(buff,"quit",4)){
printf("I will quit write!\n");
break;
}
write(newfd,buff,strlen(buff));
}
}
return 0;
}
/***** client.c *****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc,char** argv){
if(argc <2){
printf("the argument's num less 2\n");
return 0;
}
int nowfd;
struct sockaddr_in nowaddr;
char buff[1024];
bzero(&nowaddr,sizeof(nowaddr));
nowaddr.sin_family = AF_INET;
nowaddr.sin_port = htons(6666);
if(inet_pton(AF_INET,argv[1],&nowaddr.sin_addr) < 0){
printf("inet convert error!\n");
return 0;
}
if((nowfd = socket(AF_INET,SOCK_STREAM,0)) < 0){
printf("socket create error!\n");
return 0;
}
if(connect(nowfd,(struct sockaddr*)&nowaddr,sizeof(struct sockaddr)) < 0){
printf("connect error!\n");
return 0;
}
pid_t pid = fork();
if(pid == 0){
while(1){
bzero(buff,sizeof(buff));
int len = recv(nowfd,buff,sizeof(buff)-1,0);
if(!strncasecmp(buff,"quit",4)){
printf("I will quit read\n");
break;
}
if(len > 0){
printf("I have recvive : %s\n",buff);
}
}
} else{
while(1){
bzero(buff,sizeof(buff));
fgets(buff,sizeof(buff),stdin);
if(!strncasecmp(buff,"quit",4)){
printf("I will quit write\n");
break;
}
send(nowfd,buff,strlen(buff)-1,0);
}
}
close(nowfd);
return 0;
}
运行
1.编译 Makefile
all:server client
server:server.o
gcc server.o -o server
client:client.o
gcc client.o -o client
server.o:server.cpp
gcc -c server.cpp
client.o:client.cpp
gcc -c client.cpp
2.在一个终端执行
./server
3.在另一个终端执行
./client 127.0.0.1
这样两个终端就可以通信啦!!!