理解网络编程和套接字
基础
在计算机网络当中,我们需要进行以下步骤进行网络通信:
-
构建套接字
#include<sys/socket.h> int socket(int domain,int type,int protocol);//成功则返回文件描述符,失败返回-1
-
调用bind函数给套接字分配本机地址
#incude<sys/socket.h> int bind(int sockfd,struct sockaddr *myaddr,socklen_t addrlen);//成功返回0,失败返回-1
-
如果是服务端则调用listen进行连接监听,然后调用accept接受请求;如果是客户端则调用connect进行请求连接。
#include<sys/socket.h> int listen(int sockfd,int backlog); int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen); int connect(int sockfd,struct sockaddr *serv_addr,socklen_t addrlen);
以上每个动作都有相应的函数完成。
实例
-
服务端(hello_serve.c )
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> void error_handling(char *message); int main(int argc, char *argv[]) { int serv_sock; int clnt_sock; struct sockaddr_in serv_addr; struct sockaddr_in clnt_addr; socklen_t clnt_addr_size; char message[]="Hello world"; if(argc!=2) { printf("Usage:%s <port>\n",argv[0]); exit(1); } //调用socket函数创建套接字 serv_sock=socket(PF_INET,SOCK_STREAM,0); if(serv_sock==-1)error_handling("sock() error"); memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family=AF_INET; serv_addr.sin_addr.s_addr=htonl(INADDR_ANY); serv_addr.sin_port=htons(atoi(argv[1])); //调用bind()函数分配IP地址以及端口号 if(bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) error_handling("bind() error"); //调用listen()函数将套接字转为可接收连接的状态 if(listen(serv_sock,5)==-1) error_handling("listen() error"); clnt_addr_size=sizeof(clnt_addr); //调用accept函数受理连接请求。该函数属于阻塞型函数,直到有连接请求才会执行下面的程序 clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_addr_size); if(clnt_sock==-1) error_handling("accept() error"); //连接完成之后,系统将套接字看做为一个文件(句柄为socket返回的文件描述符) write(clnt_sock,message,sizeof(message)); close(clnt_sock); close(serv_sock); return 0; } void error_handling(char *message) { fputs(message,stderr); fputc('\n',stderr); exit(1); }
-
客户端(hello_client.c )
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> void error_handling(char *message); int main(int argc,char* argv[]) { int sock; struct sockaddr_in serv_addr; char message[30]; int str_len; if(argc!=3) { printf("Usage:%s <IP> <port>\n",argv[0]); exit(1); } //创建套接字 sock=socket(PF_INET,SOCK_STREAM,0); if(sock==-1)error_handling("socket() error"); memset(&serv_addr,0,sizeof(serv_addr)); serv_addr.sin_family=AF_INET; serv_addr.sin_addr.s_addr=inet_addr(argv[1]); serv_addr.sin_port=htons(atoi(argv[2])); //向服务器发送请求连接请求,这个函数同时也代表这个是客户端而非服务端 if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) error_handling("connect error"); //读取来自服务器的消息,-1表示去除尾端的结束符EOF str_len=read(sock,message,sizeof(message)-1); if(str_len==-1) error_handling("read() error"); printf("Message from serve:%s \n",message); close(sock); return 0; } void error_handling(char* message) { fputs(message,stderr); fputc('\n',stderr); exit(1); }
-
编译运行
编译:
gcc hello_serve.c -o serve
gcc hello_client -o client
运行:
先启用服务端并指明监听端口:./serve 9091
然后启用客户端需要同时指明服务端的IP地址以及服务端的监听端口,由于是在本地循环,因此使用本地测试IP地址:./client 127.0.0.1 9091
我会不断更新,欢迎关注我的专栏!