socket(AF_INET, SOCK_STREAM, 0)
socket函数是为了创建服务器端的套接字,是用来监听是否有客户端来连接的;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)
setsockopt是为了设置端口复用,opt设置为1;
bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)
bind函数是为了将服务端的地址结构(IP+端口)绑定到套接字上;
listen(lfd, 128)
listen函数是为了设置监听上限的,不是阻塞监听;
在接收到客户端的请求之后,需要分配主线程和子线程的工作:
主线程:将子线程分离出进程,使其不会影响后续的接收,子线程结束后,自行回收结束
子线程:使用读写的套接字与客户端进行通信
cfd = accept(lfd,(struct sockaddr*)&cli_addr, &cli_addr_len)
accept函数阻塞监听客户端的连接,如果监听到连接之后就会得到客户端的地址结构和与该客户端通信的套接字。
pthread_create(tid, NULL, do_work, (void *)&cfd)
pthread_create函数创建子线程并去执行子线程对应的回调函数;
pthread_server.h代码如下:
#ifndef __PTHREAD_SERVER_H_
#define __PTHREAD_SERVER_H_
#include<iostream>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<strings.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
using namespace std;
class PthreadTcp{
public:
PthreadTcp(string note){
cout << note << endl;
}
int Socket(int domain, int type, int protocol){
int lfd = socket(domain, type, protocol);
if (lfd == -1){
cout << "socket() fail: " << strerror(errno) << endl;
exit(1);
}
return lfd;
}
void setAddr(struct sockaddr_in& ser_addr, int flg){
bzero(&ser_addr, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(8888);
if (flg == 1)
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
else
inet_pton(AF_INET, "127.0.0.1", &ser_addr.sin_addr.s_addr);
}
void setSockOpt(int lfd){
int opt = 1;
int ret = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (ret == -1){
cout << "setsockopt() fail:" << strerror(errno) << endl;
}
}
void Bind(int lfd, const struct sockaddr* ser_addr, socklen_t ser_len){
int ret = bind(lfd, ser_addr, ser_len);
if (ret == -1){
cout << "bind() fail :" << strerror(errno) << endl;
exit(1);
}
}
void Listen(int lfd, int backlog){
int ret = listen(lfd, backlog);
if (ret == -1){
cout << "listen() fail :" << strerror(errno) << endl;
exit(1);
}
}
int Accept(int lfd, struct sockaddr* cli_addr, socklen_t* cli_len){
int cfd;
do{
cfd = accept(lfd, cli_addr, cli_len);
if (cfd == -1){
if (errno == EINTR)
continue;
else {
cout << "accept() --- error: " << strerror(errno) << endl;
exit(0);
}
}
}while(0);
return cfd;
}
int Connect(int cfd, const struct sockaddr *addr, socklen_t addrlen){
int ret = connect(cfd, addr, addrlen);
if (ret == -1){
cout << "connect() fail: " << strerror(errno) << endl;
exit(1);
}
return ret;
}
int Read(int fd, void *buf, size_t count){
int ret = read(fd, buf, count);
if (ret == 0){
close(fd);
cout << "the client close connection!!!" << endl;
exit(0);
} else if (ret == EAGAIN){
cout << "the error is EAGAIN" << endl;
exit(1);
} else if (ret > 0){
return ret;
}
return ret;
}
int Write(int fd, const void *buf, size_t count){
int ret = write(fd, buf, count);
return ret;
}
};
#endif
pthread_server.cpp代码如下:
#include "pthread_server.h"
#include<ctype.h>
PthreadTcp *tcp ;
void* do_work(void* arg){
int ret, n, cfd;
char buf[BUFSIZ];
cfd = *((int*)arg);
while((n = tcp->Read(cfd, buf, sizeof(buf))) != -1){
if (n == 0){
close(cfd);
pthread_exit(NULL);
}
for (int i = 0; i < n; i ++){
buf[i] = toupper(buf[i]);
}
tcp->Write(cfd, buf, n);
tcp->Write(STDOUT_FILENO, buf, n);
}
}
int main()
{
int cfd;
pthread_t tid;
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_addr_len = sizeof(cli_addr);
tcp = new PthreadTcp("server working\n");
int lfd = tcp->Socket(AF_INET, SOCK_STREAM, 0); //创建服务器端套接字
tcp->setSockOpt(lfd); //设置端口复用
tcp->setAddr(serv_addr, 1); //设置服务器端地址结构
tcp->Bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); //绑定地址结构
tcp->Listen(lfd, 128);
cout << "server start receive client's message" << endl;
while(1){
cfd = tcp->Accept(lfd, (struct sockaddr*)&cli_addr, &cli_addr_len);
pthread_create(&tid, NULL, do_work, (void *)&cfd);
pthread_detach(tid);
}
return 0;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。