前言
在上节课(Linux网络编程初体验)中我们实现了连接bilibili的功能,并获取其html源码
如图所示.
今天我们要自己编写个服务端来服务我们的客户端
提示:以下是本篇文章正文内容,下面案例可供参考
服务端是啥、有什么特点
服务端长期暴露于网络,并等待客户端连接
特点:
服务端无法主动连接客户端
客户端只能按照预定义的方式连接服务端
服务端编程模式:
socket()->bind()->listen()->accept()->client_sock-> send()/recv->close()
核心函数
int bind(int sock,struct sockaddr*addr,socklen_t addrlen);//参数1:服务端sock,参数2:服务端sockaddr,参数3:参数2的大小,类型为socklen_t int listen(int sock,int backlog);//参数1:服务端sock,参数2:直接填1 int accept(int sock,struct sockaddr*addr,socklen_t*addrlen);//参数1:客户端sock,参数2接受客户端addr的地址,参数3:参数2的长度
accept()的返回值为客户端的sock
socket的简介
服务端socket只用于连接,不进行通讯
服务端的socket用于产生客户端的socket
socket还可以提供不同类型的通信功能(本地、局域网等)
服务器编程
头文件:
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h> #include <string.h>
定义服务端的socket和sockaddr_inint server = 0; struct sockaddr_in saddr = {0};
定义要通信的客户端的socket和sockaddr_inint client = 0; struct sockaddr_in caddr = {0};
定义客户端sockaddr_in 的长度变量socklen_t asize = 0;
以及其他的变量
int len = 0;//发送和接收的字符串长度 char buf[32] = {0};//接收区 int r = 0;//循环控制变量
创建socket
server = socket(PF_INET, SOCK_STREAM, 0); if( server == -1 ) { printf("server socket error\n"); return -1; }
赋值服务端的sockaddr_in
saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY:同一wifi下的主机地址都可以 saddr.sin_port = htons(8899);
绑定以及监听
if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 ) { printf("server bind error\n"); return -1; } if( listen(server, 1) == -1 ) { printf("server listen error\n"); return -1; }
等待客户端的连接
while(1) { asize = sizeof(caddr);//客户端sockaddr_in大小 client = accept(server, (struct sockaddr*)&caddr, &asize); if( client == -1 ) { printf("client accept error\n"); return -1; } printf("client: %d\n", client); }
接收和发送数据:
do { r = recv(client, buf, sizeof(buf), 0); if( r > 0 ) { printf("Receive: %s\n", buf); if( strcmp(buf, "quit") != 0 )//当字符串为quit时,退出 { len = send(client, buf, r, 0); break; } else { break; } } } while ( r > 0 );
注意:这里的代码在while(1)里面
代码全貌:
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h> #include <string.h> int main() { int server = 0; struct sockaddr_in saddr = {0}; int client = 0; struct sockaddr_in caddr = {0}; socklen_t asize = 0; int len = 0;server char buf[32] = {0}; int r = 0; server = socket(PF_INET, SOCK_STREAM, 0); if( server == -1 ) { printf("server socket error\n"); return -1; } saddr.sin_fami0ly = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons(8888); if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 ) { printf("server bind error\n"); return -1; } if( listen(server, 1) == -1 ) { printf("server listen error\n"); return -1; } printf("server start success\n"); while( 1 ) { asize = sizeof(caddr); client = accept(server, (struct sockaddr*)&caddr, &asize); if( client == -1 ) { printf("client accept error\n"); return -1; } printf("client: %d\n", client); do { r = recv(client, buf, sizeof(buf), 0); if( r > 0 ) { printf("Receive: %s\n", buf); if( strcmp(buf, "quit") != 0 ) { len = send(client, buf, r, 0); break; } else { break; } } } while ( r > 0 ); close(client); } close(server); return 0; }
客户端代码
复用上期的服务端
改动:
1、定义input变量,让用户自己输入字符发送给服务端char input[32] = {0};
2、端口号和ip地址
ip地址:在TerMinal中输入ifconfig
可以看到ip地址。如下图
端口号:要和服务器中的一样(8899)
收发数据代码:
while(1) { printf("Input: "); scanf("%s", input); len = send(sock, input, strlen(input) + 1, 0); r = recv(sock, buf, sizeof(buf), 0); if( r > 0 ) { printf("Receive: %s\n", buf); } else { break; } }
客户端代码全貌:
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h> #include <string.h> int main() { int sock = 0; struct sockaddr_in addr = {0}; int len = 0; char buf[128] = {0}; char input[32] = {0}; int r = 0; sock = socket(PF_INET, SOCK_STREAM, 0); if( sock == -1 ) { printf("socket error\n"); return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("192.168.254.128"); addr.sin_port = htons(8899); if( connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1 ) { printf("connect error\n"); return -1; } printf("connect success\n"); while( 1 ) { printf("Input: "); scanf("%s", input); len = send(sock, input, strlen(input) + 1, 0); r = recv(sock, buf, sizeof(buf), 0); if( r > 0 ) { printf("Receive: %s\n", buf); } else { break; } } close(sock); return 0; }
The End
大家可以使用下面2个命令编译我们写好的东西:
gcc -o 编译后的文件名.o 编译的文件名.c ./编译后的文件名.o
注意:要先开服务端!!!