C++编写基础Socket
Scocket的建立的过程就像拨打电话
简单来说需要这些步骤
一:建立服务端(server)
1.创建套接字(socket),和套接字结构体(用于存储IP地址和端口,网络类型等信息)
2.将套接字结构体和套接字描述符(socketfd)绑定(bind)在一起
3.开始监听(listen)
4.开始接收(accept)信息,此时处于阻塞状态,如果没有收到信息将一直阻塞在这里,收到信息则会返回socket的文件描述符。
二:建立客户端(client)
1.创建套接字(socket),和套接字结构体(用于存储目标IP地址和端口,网络类型等信息)
2.开始连接(connet),绑定符合其储存的目标信息的socket。
三:互发数据(recv,send)
经过上面两个步骤,服务端先建立,客户端再连接,这两个socket已经能够通信了。
linux提供了众多API 可以直接读取Sockfd的内容再将其存入到指定的string中。
这里我使用了send(),recv()。互发数据的步骤如下图。
TIPS:这里有一点需要特别注意,如果想要持续的互发数据,那么每次recv()到数据之后,一定要send()回去给另一端。不然另一端不知道这边到底有没有接收完毕,那么还处于send的阻塞状态。
导致客户端只能给服务端发送一次数据,客户端就进入了(send)阻塞状态。这里博主自己踩了坑,研究了两天。
基础的讲完了,然后上代码
server.cpp
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#define MAXLINE 1024
int main(int argc,char **argv){
int listenfd,connfd;//这两个稍后用作socket文件描述符
struct sockaddr_in sockaddr;//用作储存sock相关信息的结构体
char buff[MAXLINE];
int n;
char *copy = "copy that";
memset(&sockaddr,0,sizeof(sockaddr));//清空sockaddr的内容
sockaddr.sin_family = AF_INET;//AF_INET代表socket范围是IPV4的网络
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY代表不管数据包目标地址是哪里都接收
sockaddr.sin_port = htons(10004);//htons代表将本地字节序(port信息)转化成网络字节序,
listenfd = socket(AF_INET,SOCK_STREAM,0);//创建IPV4(AF_INET)的TCP(SOCK_STREAM)的socket
bind(listenfd,(struct sockaddr *) &sockaddr,sizeof(sockaddr));//将socket与sockaddr绑定
listen(listenfd,1024);//开始监听,最长字符串长度1024
printf("Please wait for the client information\n");
if((connfd = accept(listenfd,(struct sockaddr*)NULL,NULL))==-1)//进入接收阻塞状态,直到收到信息
{
printf("accpet socket error: %s errno :%d\n",strerror(errno),errno);
exit(0);
}
for(;;){
n = recv(connfd,buff,MAXLINE,0);//recvAPI可以获取规定字符长度sockfd的内容到指定buffer
buff[n+1] = '\0';//添加文件结束符
printf("recv msg from client:%s\n",buff);
send(connfd,copy,strlen(copy),0);//将收到的消息发送给客户端,提示这边已经接收完毕
memset(buff,0,sizeof(buff));//清空buff内容
}
close(connfd);//关闭accept的文件描述符
close(listenfd);//关闭socketfd的文件描述符
return 0;
}
client.cpp
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXLINE 1024
int main(int argc,char **argv)
{
char *servInetAddr = "127.0.0.1";//127.0.0.1是具有特殊意义的ip地址,代表本地回环,可以用于测试
int socketfd;//创建socket文件描述符
struct sockaddr_in sockaddr;//创建socket结构体,准备存入相关信息
char recvline[MAXLINE], sendline[MAXLINE];//用来存收到的数据,和即将发送出去的数据
int n;
socketfd = socket(AF_INET,SOCK_STREAM,0);//创建IPV4(AF_INET)的TCP(SOCK_STRAM)的socket
memset(&sockaddr,0,sizeof(sockaddr));//重置结构体内容
sockaddr.sin_family = AF_INET;//作用范围是IPV4的网络
sockaddr.sin_port = htons(10004);//将10004转化为网络字节序
inet_pton(AF_INET,servInetAddr,&sockaddr.sin_addr);//这个API可以将其中的参数转化为网络字节序,并存入socket结构体中。实际上这里也可以用sockaddr_in.in_addr.sin_addr=htonl(127.0.0.1)来存IP的信息
if((connect(socketfd,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) < 0 )//开始连接信息匹配的socket
{
printf("connect error %s errno: %d\n",strerror(errno),errno);
exit(0);
}
for(;;){
printf("send message to server\n");
fgets(sendline,1024,stdin);//从终端获取用户输入数据
if((send(socketfd,sendline,strlen(sendline),0)) < 0)//发送给服务端
{
printf("send mes error: %s errno : %d",strerror(errno),errno);
exit(0);
}
memset(sendline,0,sizeof(sendline));//将sendline内容清空
int length = recv(socketfd,recvline,MAXLINE,0);//开始进入接收阻塞状态,直到客户端返回信息,这里接收完毕
recvline[length+1] = '\0';
printf("%s:receive messag from server:%s\n",__FILE__,recvline);//输出信息到终端
memset(recvline,0,sizeof(recvline));//将recvline内容清空
}
close(socketfd);//关闭socket,服务端会收到客户端关闭的信息,也关闭自己的socket。
printf("exit\n");
exit(0);
}
将上面两个文件编译好,同一台主机客户端和服务端可以通信,如果要在广域网通信,可修改目标IP地址(不过还没试过)。
我没用cout,好吧其实这就是C编写的(ヾ(≧▽≦*)o)
进阶内容(付费内容)
欢迎查看《The Linux Programming Interface》56章~61章。
书的链接在此:http://1.droppdf.com/files/87BCs/the-linux-programming-interface.pdf (需要技术上网,国内的资源我还没找到)
参考的博客,以下两个博客都对结构体成员参数作出了解释,不同的参数对应不同的Socket功能,比如IPV6,UDP发送等等。
:https://www.cnblogs.com/yusenwu/p/4579167.html (没有实现持续通信)
:https://www.jianshu.com/p/3b233facd6bb (实现了持续通信,并输出了客户端的IP地址端口等信息)
posted on 2021-07-14 23:56 EasternCabbage 阅读(280) 评论(0) 编辑 收藏 举报