SERVER:
#include <iostream>
#include <sys/socket.h>
#include <string>
int main()
{
//创建socket
int sockfd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
if(sockfd < 0)
{
printf("create %d %s", errno, strerror(errno));
return -1;
}
//绑定socket
string ip = "127.0.0.1";
int port = 8080;
struct sockaddr_in sockaddr;
std::memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(ip.c_str());//转成网络地址
sockaddr.sin_port = htons(port);//
if (bind(sockfd, (struct sockaddr *)&sockaddr,sizeof(sockaddr))) < 0)
{
printf("bind %d %s", errno, strerror(errno));
close(sockfd);
return -1;
}
//监听
if(listen(sockfd, 1024) < 0)
{
printf("listen %d %s", errno, strerror(errno));
close(sockfd);
return -1;
}
while(true)
{
//接收客户端链接
int connfd = accept(sockfd,nullptr,nullptr);
if(connfd < 0)
{
printf("accept %d %s", errno, strerror(errno));
break;
//return -1;
}
//接收数据
char buff[1024] = {0};
size_t len = recv(connfd,buff,sizeof(buff),0);
//发送数据
char sendbuff[1024] = "4444444";
send(connfd,sendbuff,sizeof(sendbuff),0);
//需要的话可以close
close(connfd);
}
close(sockfd);
return 0;
}
CLIENT:
#include <iostream>
int main()
{
//创建socket
int sockfd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
if(sockfd < 0)
{
printf("create %d %s", errno, strerror(errno));
return -1;
}
//链接服务器
string ip = "127.0.0.1";
int port = 8080;
struct sockaddr_in sockaddr;
std::memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_fanily = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(ip.c_str());
sockaddr-sin_port = htons(port);
if(connect(sockfd,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) < 0)
{
printf("connect %d %s", errno, strerror(errno));
close(sockfd);
return -1;
}
//发送数据
string data = "33333";
send(sockfd, data.c_str(),data.size(),0)
//接收数据
char buff[1024] = {0};
recv(sockfd,buff,sizeof(buff),0);
close(sockfd);
return 0;
}
SOCK封装
class Socket
{
public:
Socket();
~Socket();
bool bind(const string &ip, int port);
bool listen(int flag);
bool connect(const string &ip, int port);
int accept();
int send(const char* buff, int bufflen);
int recv(char* buff, int bufflen);
void close();
private:
string m_ip;
int m_port;
int m_sockfd;
};
Socket::Socket():m_ip(""), m_port(0),m_sockfd(0)
{
m_sockfd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
if(m_sockfd < 0)
{
printf("create %d %s", errno, strerror(errno));
}
}
Socket::~Socket()
{
close();
}
bool Socket::bind(const string &ip, int port)
{
struct sockaddr_in sockaddr;
std::memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
if(ip.empty())
{
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定任意网卡并转成网络地址
}
else
{
sockaddr.sin_addr.s_addr = inet_addr(ip.c_str());//转成网络地址
}
sockaddr.sin_port = htons(port);//
if (bind(m_sockfd, (struct sockaddr *)&sockaddr,sizeof(sockaddr))) < 0)
{
printf("bind %d %s", errno, strerror(errno));
close(sockfd);
return false;
}
m_ip = ip;
m_port = port;
return true;
}
void Socket::close()
{
if(m_sockfd > 0)
{
::close(m_sockfd);
}
}
阻塞IO 当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会 处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用 户线程才解除阻塞状态。
非阻塞IO 当用户线程发起read操作后,并不需要等待,而是马上得到结果。如果结果是一个error时,它就知道数据还没 有准备好,于是它可以再次发起read操作。如果内核中的数据准备好了,它就将数据拷贝到用户线程。
在非阻塞IO模型中,用户线程需要不断地轮询内核数据是否就绪,也就是说非阻塞IO不会交出CPU,而会一直占用CPU。
发送快,网卡从缓冲区取得慢,就会阻塞,缓冲区大小可以设置,都有默认大小
setsockopt(fd, SOL_SOCKET,SO_SNDBUF,1024)
setsockopt(fd, SOL_SOCKET,SO_RCVBUF,1024)
地址复用
fcntl函数:
在socket编程中,我们常用的是F_GETFL和F_SETFL来设置非阻塞(O_NONBLOCK)等标志。
示例:将文件描述符设置为非阻塞
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
// 错误处理
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
// 错误处理
}
I/O多路复用
所有异常均未处理
#define MAX_EVENTS 10
#define PORT 8080
#define BUFFER_SIZE 1024
int main()
{
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd;
struct sockaddr_in address;
listen_sock = socket(AF_INET,SOCK_STREAM,0);
//设置socket选项
int opt = 1;
setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt);//地址复用
address.sin_famiy = AF_INET;
address.sin_addr.s_addr = INADDR_ANT;
address.sin_port = htons(PORT);
bind(listen_sock, (atruct socladdr*)&address,sizeof(address));
listen(listen_sock,10);
//创建epoll
epollfd = epoll_create(0);
//创建事件
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
//添加到epoll
epoll_ctl(epollfd,EPOLL_CTL_ADD,listen_sock,&ev);
while(true)
{
nfds = epoll_wait(epollfd,events,MAX_EVENTS,-1);
for(int i = 0;i < nfds;i++)
{
if(events[i].data.fd == listen_sock)
{
conn_sock = accept(listen_sock,NULL,NULL);
struct epoll_event epoll_e;
epoll_e.events = EPOLLIN | EPOLLET;
epoll_e.data.fd = conn_sock;
epoll_ctl(epollfd,EPOLL_CTL_ADD,conn_sock,&epoll_e);
}
else if(events[i].data.fd == conn_sock)
{
char buff[1024] = {0};
read(events[i].data.fd,buff,sizeof(buff));
}
}
}
}