#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 <unistd.h>
#include <iostream>
using namespace std;
#define DEFAULT_PORT 8000
#define MAXLINE 4096
struct Packet
{
unsigned int msgLen; //数据部分的长度(注:这是网络字节序)
char text[1024]; //报文的数据部分
};
/**实现:
这两个函数只是按需多次调用read和write系统调用直至读/写了count个数据
**/
/**返回值说明:
== count: 说明正确返回, 已经真正读取了count个字节
== -1 : 读取出错返回
< count: 读取到了末尾
**/
ssize_t readn(int fd, void *buf, size_t count)
{
size_t nLeft = count;
ssize_t nRead = 0;
char *pBuf = (char *)buf;
while (nLeft > 0)
{
if ((nRead = read(fd, pBuf, nLeft)) < 0)
{
//如果读取操作是被信号打断了, 则说明还可以继续读
if (errno == EINTR)
continue;
//否则就是其他错误
else
return -1;
}
//读取到末尾
else if (nRead == 0)
return count-nLeft;
//正常读取
nLeft -= nRead;
pBuf += nRead;
}
return count;
}
/**返回值说明:
== count: 说明正确返回, 已经真正写入了count个字节
== -1 : 写入出错返回
**/
ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nLeft = count;
ssize_t nWritten = 0;
char *pBuf = (char *)buf;
while (nLeft > 0)
{
if ((nWritten = write(fd, pBuf, nLeft)) < 0)
{
//如果写入操作是被信号打断了, 则说明还可以继续写入
if (errno == EINTR)
continue;
//否则就是其他错误
else
return -1;
}
//如果 ==0则说明是什么也没写入, 可以继续写
else if (nWritten == 0)
continue;
//正常写入
nLeft -= nWritten;
pBuf += nWritten;
}
return count;
}
bool sendMessage(int clientfd,Packet buf){
unsigned int lenHost = strlen(buf.text);
buf.msgLen = htonl(lenHost);
if (writen(clientfd, &buf, sizeof(buf.msgLen)+lenHost) == -1)
return false;
return true;
}
void hander(int clientfd,struct Packet buf){
cout<<"开始处理"<<endl;
//cout<<buf.msgLen<<buf.text;
// string cmd = string(buf.text);
cout<<strlen(buf.text)<<" "<<buf.text<<endl;
if(buf.text == "结束"){
close(clientfd);
cout<<"结束进程"<<endl;
exit(0);
}
cout<<"处理结束"<<endl;
sendMessage(clientfd,buf);
}
void echo(int clientfd)
{
struct Packet buf;
int readBytes;
memset(&buf,0,sizeof(buf));
//首先读取首部
while ((readBytes = readn(clientfd, &buf.msgLen, sizeof(buf.msgLen))) > 0)
{
//网络字节序 -> 主机字节序
int lenHost = ntohl(buf.msgLen);
//然后读取数据部分
readBytes = readn(clientfd, buf.text, lenHost);
if (readBytes == -1){
cerr << "readn socket error..." << endl;
exit(1);//err_exit("readn socket error");
}else if (readBytes != lenHost)
{
cerr << "client connect closed..." << endl;
return ;
}
//cout <<lenHost <<" "<<buf.text<<endl;
hander(clientfd,buf);
memset(&buf,0,sizeof(buf));
}
if (readBytes == -1) //err_exit("read socket error");
cerr << "read socket error" << endl;
else if (readBytes != sizeof(buf.msgLen))
cerr << "client connect closed..." << endl;
}
int Init(int port){
int socket_fd, connect_fd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
//初始化Socket
if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
//初始化
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。
servaddr.sin_port = htons(port);//设置的端口为DEFAULT_PORT
//将本地地址绑定到所创建的套接字上
if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
//开始监听是否有客户端连接
if( listen(socket_fd, 10) == -1){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
return socket_fd;
}
int accept(int socket_fd){
int connect_fd;
printf("======waiting for client's request======\n");
//阻塞直到有客户端连接,不然多浪费CPU资源。
if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
}
return connect_fd;
}
int main(int argc, char** argv)
{
int sockfd = Init(8000);
int connect_fd = accept(sockfd); // 阻塞
if(!fork()){
cout<<"开始echo"<<endl;
echo(connect_fd);
}
close(connect_fd);
close(sockfd);
}
Linux socket 服务器
最新推荐文章于 2024-05-04 22:58:13 发布