一、简介
二、详解
简单socket服务器和客户端(基础)
服务器:
/*
* socket简单编程 服务端
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define BUFFSIZE 1024
int main(int argc, char *argv[])
{
int server_sockfd = 0;
int client_sockfd = 0;
int len = 0;
int sin_size = 0;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
char buf[BUFFSIZE] = {0};
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8000);
if((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error!\n");
return -1;
}
if(bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0)
{
perror("bind error!\n");
return -1;
}
if(listen(server_sockfd, 5) < 0)
{
perror("listen error!\n");
return -1;
}
sin_size= sizeof(struct sockaddr_in);
if((client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &sin_size)) < 0)
{
perror("accept error!\n");
return -1;
}
printf("accept client %s\n",inet_ntoa(client_addr.sin_addr));
len = send(client_sockfd, "Hello word!\n",30,0);
while((len = recv(client_sockfd, buf, BUFFSIZE, 0)) >0)
{
buf[len] = '\0';
printf("buf = %s\n",buf);
if(send(client_sockfd, buf, len, 0) < 0)
{
perror("send error!\n");
return -1;
}
}
close(client_sockfd);
close(server_sockfd);
return 0;
}
客户端:
/*
* socket简单编程 客户端
*/
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define BUFFSIZE 1024
int main(int argc, char *argv[])
{
int client_sockfd = 0;
int len = 0;
struct sockaddr_in server_addr;
char buf[BUFFSIZE] = {0};
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(8000);
if((client_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error!\n");
return -1;
}
if(connect(client_sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0)
{
perror("client error!\n");
return -1;
}
printf("connect success!\n");
len = recv(client_sockfd, buf, BUFFSIZE, 0);
buf[len] = '\0';
printf("client_buf = %s\n",buf);
while(1)
{
printf("Enter string to send:");
scanf("%s",buf);
if(!strcmp(buf,"quit"))
{
break;
}
len = send(client_sockfd, buf, strlen(buf), 0);
len = recv(client_sockfd, buf, BUFFSIZE, 0);
buf[len] = '\0';
printf("received: %s\n",buf);
}
close(client_sockfd);
return 0;
}
(1)多线程并发服务器server.c
//使用pthread线程库
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>
#define PORT 1234 //服务器端口
#define BACKLOG 5 //listen队列等待的连接数
#define MAXDATASIZE 1024 //缓冲区大小
void process_cli(int connectfd, struct sockaddr_in client); //客户端请求处理函数
void* start_routine(void* arg); //线程函数
typedef struct _ARG {
int connfd;
struct sockaddr_in client;
}ARG; //客户端结构体
void main()
{
int listenfd, connectfd; //socket描述符
pthread_t thread; //线程体变量
ARG *arg; //客户端结构体变量
struct sockaddr_in server; //服务器地址信息结构体
struct sockaddr_in client; //客户端地址信息结构体
int sin_size;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { //调用socket,创建监听客户端的socket
perror("Creating socket failed.");
exit(1);
}
int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //设置socket属性,端口可以重用
//初始化服务器地址结构体
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) { //调用bind,绑定地址和端口
perror("Bind error.");
exit(1);
}
if(listen(listenfd,BACKLOG) == -1){ //调用listen,开始监听
perror("listen() error\n");
exit(1);
}
sin_size=sizeof(struct sockaddr_in);
while(1) {
if ((connectfd = accept(listenfd,(struct sockaddr *)&client,(socklen_t *)&sin_size))==-1) {
//调用accept,返回与服务器连接的客户端描述符
perror("accept() error\n");
exit(1);
}
arg = new ARG;
arg->connfd = connectfd;
memcpy(&arg->client, &client, sizeof(client));
if (pthread_create(&thread, NULL, start_routine, (void*)arg)) { //创建线程,以客户端连接为参数,start_routine为线程执行函数
perror("Pthread_create() error");
exit(1);
}
}
close(listenfd); //关闭监听socket
}
void process_cli(int connectfd, sockaddr_in client)
{
int num;
char recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];
printf("You got a connection from %s. ",inet_ntoa(client.sin_addr) );
num = recv(connectfd, cli_name, MAXDATASIZE,0);
if (num == 0) {
close(connectfd);
printf("Client disconnected.\n");
return;
}
cli_name[num - 1] = '\0';
printf("Client's name is %s.\n",cli_name);
while (num = recv(connectfd, recvbuf, MAXDATASIZE,0)) {
recvbuf[num] = '\0';
printf("Received client( %s ) message: %s",cli_name, recvbuf);
for (int i = 0; i < num - 1; i++) {
sendbuf[i] = recvbuf[num - i -2];
}
sendbuf[num - 1] = '\0';
send(connectfd,sendbuf,strlen(sendbuf),0);
}
close(connectfd);
}
void* start_routine(void* arg)
{
ARG *info;
info = (ARG *)arg;
process_cli(info->connfd, info->client);
delete info;
pthread_exit(NULL);
}
客户端:
#include <iostream>
using namespace std;
string m_strIP = "172.168.1.242";
int m_nPort = 15003;
void main()
{
int fd;
int retcode;
int recv_count;
char *rcvbuf;
struct sockaddr_in addr;
struct timeval timeo = {10, 0};
unsigned long flags;
memset(&addr,0x00,sizeof(struct sockaddr_in));
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(m_strIP);
addr.sin_port = htons(m_nPort);
//flags = fcntl(fd, F_GETFL, 0);
//fcntl(fd, F_SETFL, flags | O_NONBLOCK);
retcode = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
recv_count = recv(fd, rcvbuf, 26, 0);
cout<<recv_count<<endl;
cout<<rcvbuf<<endl
if(0 == retcode)
{
if (fcntl(fd, F_SETFL, flags) < 0)
{
cout<<"Connect error!"<<endl;
return -1;
}
else
{
cout<<"Connect ok sockfd!"<<endl;
return fd;
}
}
}
(2)select非阻塞服务器
select单线程服务器:
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
const int MAX_CLIENT = 40;
using namespace std;
int main()
{
int m_nSocket;
sockaddr_in m_stSockaddr;
string m_strIP = "172.168.1.242";
int m_nPort = 15003;
m_nSocket = socket(AF_INET, SOCK_STREAM, 0);
if (m_nSocket < 0)
{
cout<<"Create failed!"<<endl;
return 1;
}
cout<<"socket succed!"<<endl;
fcntl(m_nSocket, F_SETFL, O_NONBLOCK); //设置socket非阻塞
int nTmp = 1;
int nRet =setsockopt(m_nSocket, SOL_SOCKET, SO_REUSEADDR, &nTmp, sizeof(int));
if (nRet < 0)
{
return 1;
}
cout<<"fcntl succed!"<<endl;
// 设置SOCKET接收地址和端口
memset (&m_stSockaddr, 0, sizeof(m_stSockaddr));
m_stSockaddr.sin_family = AF_INET;
m_stSockaddr.sin_addr.s_addr = inet_addr(m_strIP.c_str());
m_stSockaddr.sin_port = htons (m_nPort);
nRet = bind (m_nSocket, (struct sockaddr*)&m_stSockaddr,sizeof(m_stSockaddr));
if (nRet < 0)
{
return 1;
}
cout<<"bind succed!"<<endl;
nRet = listen (m_nSocket, MAX_CLIENT);
if (nRet < 0)
{
return 1;
}
cout<<"listen succed!"<<endl;
fd_set readfds;
fd_set rdfds;
struct timeval tv;
sockaddr_in clientAddr;
tv.tv_sec=60; // select超时时间
tv.tv_usec=0;
int clientfd;
FD_ZERO(&readfds);
FD_ZERO(&rdfds);
FD_SET(m_nSocket, &readfds);
while(1)
{
cout<<"connecting........."<<endl;
rdfds = readfds;
nRet=select(m_nSocket+1, &rdfds, NULL, NULL, &tv);
if(nRet > 0)
{
if(FD_ISSET(m_nSocket, &readfds))
{
clientfd = accept(m_nSocket, (struct sockaddr*)&clientAddr, &sizeof(clientAddr));
if(clientfd<0)
{
cout<<"accept error!"<<endl;
continue;
}
else
if(send (clientfd,"Hello,you are connected!\n",26,0) != -1)
{
cout<<"send succedd"<<endl;
}
close(clientfd);
}
}
}
return 0;
}
select多线程服务器:
select服务器:
socket_server.h(头文件):
#ifndef _SOCKET_SERVER_H_
#define _SOCKET_SERVER_H_
#include <iostream>
#include <errno.h>
#include <stdio.h>
using namespace std;
struct thread_param
{
void *t_this;
int sockd;
};
class socket_server
{
public:
socket_server();
virtual ~socket_server();
void socket_op();
void *sock_thread();
private:
void my_err(const char*err_string, char *function, int line);
int sock_array[10000];
int nSock;
int maxfd;
};
#endif
socket_server.cpp:
#include "socket_server.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
socket_server::socket_server()
{
memset(sock_array, 0, sizeof(sock_array));
nSock = 0;
}
socket_server::~socket_server()
{
}
void *sock_thread_proc(void *arg)
{
pthread_detach(pthread_self());
socket_server *p_sock = (socket_server *)arg;
p_sock->sock_thread();
return ((void *)0);
}
void *socket_server::sock_thread()
{
struct timeval tv;
//gettimeofday(&tv, NULL);
tv.tv_sec=10; // select超时时间
tv.tv_usec=0;
fd_set readfds;
fd_set writefds;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
int nRet;
int ret;
int i,j;
char recv_buf[128] = {0};
while(1) {
if (nSock == 0) {
sleep(4);
cout<<"nsock is zero"<<endl;
continue;
}
maxfd = sock_array[0];
FD_SET(sock_array[0], &readfds);
for (i = 1; i< nSock; i++) {
FD_SET(sock_array[i], &readfds);
if (sock_array[i] > maxfd)
maxfd = sock_array[i];
}
cout<<"maxfd:"<<maxfd<<endl;
nRet=select(maxfd + 1, &readfds, NULL, NULL, &tv);
if(nRet>0) {
for (i = 0; i < nSock; i++) {
if (FD_ISSET(sock_array[i], &readfds)) {
if ((ret = recv(sock_array[i], recv_buf, sizeof(recv_buf), 0)) < 0)
my_err("recv", __FUNCTION__, __LINE__);
if (ret > 0) {
recv_buf[ret] = '\0';
cout<<"server接受数据:"<<recv_buf<<endl;
}
else
cout<<"server无数据。"<<endl;
FD_SET(sock_array[i], &writefds);
nRet=select(sock_array[i] + 1, NULL, &writefds, NULL, &tv);
if(nRet > 0) {
if (FD_ISSET(sock_array[i], &writefds)) {
char *send_data = "接受数据成功!";
if (send(sock_array[i], send_data, strlen(send_data), 0) < 0){
my_err("send", __FUNCTION__, __LINE__);
}
cout<<"send succeed"<<endl;
}
}
else
cout<<"发送超时!"<<endl;
//关闭该套接字
close(sock_array[i]);
for (j = i; j < nSock - 1; j++) {
sock_array[j] = sock_array[j + 1];
}
nSock--;
}
}
}
else {
cout<<"接收超时!"<<endl;
break;
}
cout<<"******deal sock finish******"<<endl;
}
return ((void *)0);
}
void socket_server::my_err(const char*err_string, char *function, int line)
{
fprintf(stderr, "func[%s]line:%d\n", function, line);
perror(err_string);
exit(1);
}
void socket_server::socket_op()
{
pthread_t pid;
pthread_create(&pid, NULL, sock_thread_proc, this);
int sock_fd;
int new_sockfd;
struct sockaddr_in serv_addr;
struct sockaddr_in client_addr;
int nRet;
int i;
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
my_err("socket", __FUNCTION__, __LINE__);
fcntl(sock_fd, F_SETFL, O_NONBLOCK); //设置socket非阻塞
int optval = 1;
//可以重新绑定端口
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) < 0)
my_err("setsockopt", __FUNCTION__, __LINE__);
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(4507);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
nRet = bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in));
if (nRet < 0)
my_err("bind", __FUNCTION__, __LINE__);
nRet = listen(sock_fd, 10000);
if (nRet < 0)
my_err("listen", __FUNCTION__, __LINE__);
fd_set readfds;
FD_ZERO(&readfds);
struct timeval tv;
//gettimeofday(&tv, NULL);
tv.tv_sec = 10; // select超时时间
tv.tv_usec=0;
socklen_t addr_len = sizeof(struct sockaddr_in);
while(1) {
FD_SET(sock_fd, &readfds);
nRet=select(sock_fd + 1, &readfds, NULL, NULL, &tv);
if(nRet > 0) {
if (FD_ISSET(sock_fd, &readfds)) {
new_sockfd = accept(sock_fd, (struct sockaddr*)&client_addr, &addr_len);
sock_array[nSock++] = new_sockfd; //入数组
}
}
else if(nRet == 0) {
cout<<"waiting for connecting......"<<endl;
continue;
}
else {
cout<<"select error!"<<endl;
}
}
}
int main()
{
socket_server *obj = new socket_server();
cout<<"******socket server begin to accept client******"<<endl;
obj->socket_op();
delete obj;
return 0;
}
select客户端:
socket_client.h(头文件):
#ifndef _SOCKET_CLIENT_H_
#define _SOCKET_CLIENT_H_
#include <iostream>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class socket_client
{
public:
socket_client();
virtual ~socket_client();
void socket_connect(const int conn_timeout);
private:
void my_err(const char*err_string, char *function, int line);
};
#endif
socket_client.cpp:
#include "socket_client.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <arpa/inet.h>
socket_client::socket_client()
{
}
socket_client::~socket_client()
{
}
void socket_client::my_err(const char*err_string, char *function, int line)
{
fprintf(stderr, "func[%s]line:%d\n", function, line);
perror(err_string);
exit(1);
}
void socket_client::socket_connect(const int conn_timeout)
{
int sock_fd;
int nRet;
struct sockaddr_in addr;
fd_set rdset;
fd_set wtset;
int retval;
char sndbuff[1024] = "socket connnect to the server succeed.";
char recv_buf[1024] = {0};
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
my_err("socket", __FUNCTION__, __LINE__);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(4507);
if (fcntl(sock_fd, F_SETFL, fcntl(sock_fd, F_GETFL) | O_NONBLOCK) < 0) {
my_err("fcntl", __FUNCTION__, __LINE__);
}
nRet = connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr));
if (nRet < 0) {
my_err("fcntl", __FUNCTION__, __LINE__);
}
FD_ZERO(&wtset);
FD_SET(sock_fd, &wtset);
struct timeval tv;
tv.tv_sec = conn_timeout; // select超时时间
tv.tv_usec = 0;
retval = select(sock_fd + 1, NULL, &wtset, NULL, &tv);
if (retval == 0) {
cout<<"send timeout......"<<endl;
}
else if (retval > 0) {
if(FD_ISSET (sock_fd, &wtset)) {
if (send(sock_fd, sndbuff, strlen(sndbuff), 0) < 0)
my_err("send", __FUNCTION__, __LINE__);
cout<<"send succeed!"<<endl;
}
}
FD_ZERO(&rdset);
FD_SET(sock_fd, &rdset);
retval = select(sock_fd + 1, &rdset, NULL, NULL, &tv);
if (retval == 0) {
cout<<"recv timeout......"<<endl;
}
else if (retval > 0) {
if(FD_ISSET (sock_fd, &rdset)) {
if ((retval = recv(sock_fd, recv_buf, sizeof(recv_buf), 0)) < 0)
my_err("recv", __FUNCTION__, __LINE__);
recv_buf[retval] = '\0';
cout<<"server接受数据:"<<recv_buf<<endl;
}
}
close(sock_fd);
}
int main()
{
socket_client *obj = new socket_client();
obj->socket_connect(10);
delete obj;
return 0;
}
(3)pool非阻塞服务器和客户端
pool服务器:
socket_server.h(头文件):
#ifndef _SOCKET_SERVER_H_
#define _SOCKET_SERVER_H_
#include <iostream>
#include <errno.h>
#include <stdio.h>
#include <poll.h>
using namespace std;
struct thread_param
{
void *t_this;
int sockd;
};
class socket_server
{
public:
socket_server();
virtual ~socket_server();
void socket_op();
void *sock_thread();
void sock_recvsend(int sockfd);
private:
void my_err(const char*err_string, char *function, int line);
int sock_array[10000];
int nSock;
int maxfd;
struct pollfd fds[10000];
};
#endif
socket_server.cpp:
#include "socket_server.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <poll.h>
socket_server::socket_server()
{
pthread_mutex_init(&m_mutex, NULL);
pthread_mutex_init(&m_lock, NULL);
pthread_cond_init(&c_lock, NULL);
memset(sock_array, 0, sizeof(sock_array));
nSock = 0;
}
socket_server::~socket_server()
{
pthread_mutex_destroy(&m_mutex);
pthread_mutex_destroy(&m_lock);
pthread_cond_destroy(&c_lock);
}
void *sock_thread_proc(void *arg)
{
pthread_detach(pthread_self());
socket_server *p_sock = (socket_server *)arg;
p_sock->sock_thread();
return ((void *)0);
}
void *sock_recvsend_proc(void *arg)
{
pthread_detach(pthread_self());
thread_param *p_arg = (thread_param *)arg;
socket_server *p_sock = (socket_server *)p_arg->t_this;
p_sock->sock_recvsend(p_arg->sockd);
delete p_arg;
return ((void *)0);
}
void socket_server::sock_recvsend(int sockfd)
{
char sndbuff[32767] = {0};
int timeout = 10*1000;
int ret;
int nRet;
int count;
char recv_buf[32767] = {0};
FILE *fp = fopen("./body.txt", "r+");
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(sndbuff, 1, len, fp);
while(1) {
struct pollfd event;
memset(&event, 0, sizeof(event));
event.fd = sockfd;
event.events = POLLIN;
recv_continue:
nRet = poll((struct pollfd*)&event, 1, timeout);
if (nRet < 0) {
printf("poll error!\n");
exit(1);
}
else if (nRet > 0){ //有事件发生
if (event.revents & POLLIN) {
if ((ret = recv(event.fd, recv_buf, sizeof(recv_buf), 0)) < 0)
my_err("recv", __FUNCTION__, __LINE__);
if (ret == 0) {
cout<<"out"<<endl;
break;
}
cout<<"server接受数据:"<<ret<<":"<<strlen(recv_buf)<<endl;
recv_buf[ret] = '\0';
if(strstr(recv_buf,"Envelope>") == NULL){
goto recv_continue;
}
}
memset(&event, 0, sizeof(event));
event.fd = sockfd;
event.events = POLLOUT;
send_continue:
nRet = poll((struct pollfd*)&event, 1, timeout);
if (nRet > 0) {
if (event.revents & POLLOUT) {
if ((count = send(event.fd, sndbuff, strlen(sndbuff), 0)) < 0){
my_err("send", __FUNCTION__, __LINE__);
}
cout<<"count:"<<count<<endl;
if (count < len) {
len = len - count;
goto send_continue;
}
}
}
else {
cout<<"发送超时!"<<endl;
}
}
else if(nRet == 0) {
cout<<"waiting for connecting123......"<<endl;
continue;
}
else {
cout<<"poll error!"<<endl;
}
}
close(sockfd);
}
void *socket_server::sock_thread()
{
int timeout = 10*1000;
int nRet;
int i,j;
while(1) {
pthread_mutex_lock(&m_mutex);
int num = nSock;
pthread_mutex_unlock(&m_mutex);
while (nSock == 0) {
pthread_mutex_lock(&m_lock);
pthread_cond_wait(&c_lock, &m_lock);
pthread_mutex_unlock(&m_lock);
}
memset(fds, 0, sizeof(struct pollfd)*10000);
for (i = 0; i < nSock; i++) {
fds[i].fd = sock_array[i];
fds[i].events = POLLIN;
}
nRet = poll(fds, nSock, timeout);
if (nRet < 0) {
printf("poll error!\n");
exit(1);
}
else if (nRet > 0){ //有事件发生
for (i = 0; i < nSock; i++) {
if (fds[i].revents & POLLIN) {
pthread_t pid;
thread_param *param = new thread_param();
param->t_this = this;
param->sockd = fds[i].fd;
pthread_create(&pid, NULL, sock_recvsend_proc, param);
pthread_mutex_lock(&m_mutex);
for (j = i; j < nSock - 1;j++) {
sock_array[j] = sock_array[j + 1];
}
nSock--;
pthread_mutex_unlock(&m_mutex);
}
}
}
else {
cout<<"接收超时!"<<endl;
break;
}
}
return ((void *)0);
}
void socket_server::my_err(const char*err_string, char *function, int line)
{
fprintf(stderr, "func[%s]line:%d\n", function, line);
perror(err_string);
exit(1);
}
void socket_server::socket_op()
{
pthread_t pid;
pthread_create(&pid, NULL, sock_thread_proc, this);
int sock_fd;
int new_sockfd;
struct sockaddr_in serv_addr;
struct sockaddr_in client_addr;
int nRet;
int i;
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
my_err("socket", __FUNCTION__, __LINE__);
fcntl(sock_fd, F_SETFL, O_NONBLOCK); //设置socket非阻塞
int optval = 1;
//可以重新绑定端口
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)) < 0)
my_err("setsockopt", __FUNCTION__, __LINE__);
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(4507);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
nRet = bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in));
if (nRet < 0)
my_err("bind", __FUNCTION__, __LINE__);
nRet = listen(sock_fd, 10000);
if (nRet < 0)
my_err("listen", __FUNCTION__, __LINE__);
int timeout = 5*1000;
struct pollfd p_fds;
socklen_t addr_len = sizeof(struct sockaddr_in);
memset(&p_fds, 0, sizeof(p_fds));
p_fds.fd = sock_fd;
p_fds.events = POLLIN;
while(1) {
nRet = poll((struct pollfd*)&p_fds, 1, timeout);
if(nRet > 0) {
if (p_fds.revents & POLLIN) {
new_sockfd = accept(sock_fd, (struct sockaddr*)&client_addr, &addr_len);
pthread_mutex_lock(&m_mutex);
sock_array[nSock++] = new_sockfd; //入数组
pthread_cond_signal(&c_lock);
pthread_mutex_unlock(&m_mutex);
}
}
else if(nRet == 0) {
cout<<"waiting for connecting......"<<endl;
continue;
}
else {
cout<<"poll error!"<<endl;
}
}
close(sock_fd);
}
int main()
{
socket_server *obj = new socket_server();
cout<<"******socket server begin to accept client******"<<endl;
obj->socket_op();
delete obj;
return 0;
}
pool客户端:
socket_client.h(头文件):
#ifndef _SOCKET_CLIENT_H_
#define _SOCKET_CLIENT_H_
#include <iostream>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class socket_client
{
public:
socket_client();
virtual ~socket_client();
void socket_connect(const int conn_timeout);
private:
void my_err(const char*err_string, char *function, int line);
};
#endif
socket_client.cpp:
#include "socket_client.h"
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <poll.h>
socket_client::socket_client()
{
}
socket_client::~socket_client()
{
}
void socket_client::my_err(const char*err_string, char *function, int line)
{
fprintf(stderr, "func[%s]line:%d\n", function, line);
perror(err_string);
exit(1);
}
void socket_client::socket_connect(const int conn_timeout)
{
int sock_fd;
int nRet;
struct sockaddr_in addr;
fd_set rdset;
fd_set wtset;
int retval;
char sndbuff[81920] = {0};
FILE *fp = fopen("./file.txt", "r+");
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(sndbuff, 1, len, fp);
//cout<<len<<":"<<strlen(sndbuff)<<endl;
char recv_buf[81920] = {0};
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
my_err("socket", __FUNCTION__, __LINE__);
//int nRecvBuf = 32 * 1024;
//if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, (const char*)&nRecvBuf, sizeof(int)) < 0)
// my_err("setsockopt", __FUNCTION__, __LINE__);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("172.168.1.242");
addr.sin_port = htons(4507);
nRet = connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr));
if (nRet < 0) {
my_err("connect", __FUNCTION__, __LINE__);
}
if (fcntl(sock_fd, F_SETFL, fcntl(sock_fd, F_GETFL) | O_NONBLOCK) < 0) {
my_err("fcntl", __FUNCTION__, __LINE__);
}
cout<<"sock_fd1:"<<sock_fd<<endl;
for (int i = 0; i < 1000; i++){
int timeout = 10*1000;
struct pollfd event;
int send_count = 0;
memset(&event, 0, sizeof(event));
event.fd = sock_fd;
event.events = POLLOUT;
send_again:
retval = poll((struct polled*)&event, 1, timeout);
if (retval == 0) {
cout<<"send timeout......"<<endl;
}
else if (retval > 0) {
if(event.revents & POLLOUT) {
if ((send_count = send(event.fd, sndbuff, strlen(sndbuff), 0)) < 0)
my_err("send", __FUNCTION__, __LINE__);
cout<<"send succeed:"<<send_count<<endl;
if (send_count < len) {
len = len - send_count;
goto send_again;
}
}
}
// while (1) {
memset(&event, 0, sizeof(event));
event.fd = sock_fd;
event.events = POLLIN;
retry:
retval = poll((struct polled*)&event, 1, timeout);
if (retval == 0) {
cout<<"recv timeout......"<<endl;
}
else if (retval > 0) {
if(event.revents & POLLIN) {
memset(recv_buf, 0, sizeof(recv_buf));
//cout<<"bein"<<endl;
if ((retval = recv(event.fd, recv_buf, sizeof(recv_buf), 0)) < 0)
my_err("recv", __FUNCTION__, __LINE__);
if (retval == 0) {
break;
}
recv_buf[retval] = '\0';
cout<<"server接受数据:"<<strlen(recv_buf)<<endl;
//fwrite(recv_buf, 1, strlen(recv_buf), fd);
if(strstr(recv_buf,"Envelope>")==NULL){
//cout<<"server接受数据:"<<strlen(recv_buf)<<":"<<recv_buf<<endl;
goto retry;
}
// cout<<"server接受数据:"<<strlen(recv_buf)<<":"<<recv_buf<<endl;
}
}
//}
}
close(sock_fd);
}
int main()
{
socket_client *obj = new socket_client();
struct timeval *t_start, *t_end;
int timeuse;
int i;
t_start = new timeval();
gettimeofday(t_start, NULL);
for(i = 0; i < 1; i++)
obj->socket_connect(10);
t_end = new timeval();
gettimeofday(t_end, NULL);
timeuse = 1000000 * (t_end->tv_sec - t_start->tv_sec ) + t_end->tv_usec - t_start->tv_usec;
printf("时间为(ms):%d, %d\n", timeuse,timeuse/1000);
delete obj;
delete t_start;
delete t_end;
return 0;
}
makefile:
CC=g++
CFLAGS=-g -DDEBUG
LDFLAGS=
LIBS=
all: socket_client socket_server
socket_client: socket_client.cpp
$(CC) -o $@ $(LDFLAGS) socket_client.cpp $(LIBS)
socket_server: socket_server.cpp
$(CC) -o $@ $(LDFLAGS) socket_server.cpp $(LIBS)
clean:
rm -rf *.o socket_client socket_server
(4)epool非阻塞服务器和客户端
epool服务器:
#include <stdio.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/resource.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <strings.h>
#define MAXBUF 1024
#define MAXEPOLLSIZE 10000
int main(int argc, char *argv[])
{
int listener, new_fd, kdpfd, nfds, n, ret, curfds;
socklen_t len;
struct sockaddr_in my_addr,their_addr;
struct epoll_event ev;
struct epoll_event pevent[MAXEPOLLSIZE];
struct rlimit rt;
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
if (setrlimit(RLIMIT_NOFILE, &rt) == -1) {
perror("setrlimit");
exit(1);
}
else {
printf("设置系统资源参数成功!\n");
}
if( (listener = socket( PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
else {
printf("socket 创建成功!\n");
}
if (fcntl(listener, F_SETFL, fcntl(listener, F_GETFD, 0) | O_NONBLOCK) == -1) {
perror("fcntl");
return -1;
}
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(5000);
my_addr.sin_addr.s_addr = INADDR_ANY;
if ( bind( listener, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1 ) {
perror("bind");
exit(1);
}
else {
printf("IP 地址和端口绑定成功\n");
}
if (listen(listener, 2) == -1) {
perror("listen");
exit(1);
}
else
{
printf("开启服务成功!\n");
}
kdpfd = epoll_create(MAXEPOLLSIZE);
len = sizeof(struct sockaddr_in);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listener;
if( epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0 ) {
fprintf( stderr, "epoll set insertion error: fd=%d\n", listener );
return -1;
}
else {
printf("监听 socket 加入 epoll 成功!\n");
}
curfds = 1;
int timeout = 10*1000;
while(1) {
/* 等待有事件发生 */
nfds = epoll_wait(kdpfd, pevent, curfds, timeout);
if( nfds == -1 ) {
perror("epoll_wait");
break;
}
else if (nfds == 0) {
printf("waiting for connecting...\n");
continue;
}
for (n = 0; n < nfds; n++) {
if (pevent[n].data.fd == listener) {
new_fd = accept(listener, (struct sockaddr*)&their_addr, &len );
if( new_fd < 0 )
{
perror("accept");
continue;
}
else
{
printf("有连接来自于: %s:%d, 分配的 socket 为:%d\n",
inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
}
if (fcntl(new_fd, F_SETFL, fcntl(new_fd, F_GETFD, 0) | O_NONBLOCK) == -1)
{
perror("fcntl");
return -1;
}
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = new_fd;
if(epoll_ctl( kdpfd, EPOLL_CTL_ADD, new_fd, &ev) < 0) {
fprintf(stderr, "把 socket '%d' 加入 epoll 失败!%s\n",
new_fd, strerror(errno));
return -1;
}
curfds ++;
}
else if(pevent[n].events & EPOLLOUT){
char buf[MAXBUF + 1];
int len;
bzero(buf, MAXBUF + 1);
len = recv(pevent[n].data.fd, buf, MAXBUF, 0);
if (len > 0)
{
printf("%d接收消息成功:'%s',共%d个字节的数据\n", pevent[n].data.fd, buf, len);
}
else
{
if (len < 0)
printf("消息接收失败!错误代码是%d,错误信息是'%s'/n", errno, strerror(errno));
else
printf("recv empty\n");
close(pevent[n].data.fd);
continue;
}
if (len ==0 && errno != 11) {
epoll_ctl(kdpfd, EPOLL_CTL_DEL, pevent[n].data.fd,&ev);
curfds--;
}
}
}
}
close(listener);
close(kdpfd);
return 0;
}
epoll客户端:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#define MAXEPOLLSIZE 10000
int main()
{
int sock_fd;
struct sockaddr_in addr;
struct epoll_event ev;
struct epoll_event pevent[MAXEPOLLSIZE];
int nRet;
int count = 0;
if( (sock_fd = socket( PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
addr.sin_family = PF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(5000);
nRet = connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr));
if (nRet < 0) {
perror("connect");
return -1;
}
if (fcntl(sock_fd, F_SETFL, fcntl(sock_fd, F_GETFD, 0) | O_NONBLOCK) == -1) {
perror("fcntl");
return -1;
}
int kdpfd = epoll_create(MAXEPOLLSIZE);
int len = sizeof(struct sockaddr_in);
ev.events = EPOLLOUT | EPOLLET;
ev.data.fd = sock_fd;
if( epoll_ctl(kdpfd, EPOLL_CTL_ADD, sock_fd, &ev) < 0 ) {
fprintf( stderr, "epoll set insertion error: fd=%d\n", sock_fd);
return -1;
}
int curfds = 1;
int timeout = 10*1000;
int nfds;
while(1) {
nfds = epoll_wait(kdpfd, pevent, curfds, timeout);
if( nfds == -1 ) {
perror("epoll_wait");
break;
}
else if (nfds == 0) {
printf("waiting for connecting...\n");
continue;
}
int n;
printf("nfds:%d\n", nfds);
for (n = 0; n < nfds; n++) {
if (pevent[n].evnets & EPOLLIN) {
char send_buf[100] = "my name is aoyang";
count = send(pevent[n].data.fd, send_buf, strlen(send_buf), 0);
if (count != strlen(send_buf)) {
printf("send error!\n");
}
printf("count:%d\n", count);
epoll_ctl(kdpfd, EPOLL_CTL_DEL, pevent[n].data.fd,&ev);
curfds--;
close(pevent[n].data.fd);
return 0;
}
}
}
}
(5)其他设计
#include "user_exception.h"
#include "tcpsocket.h"
#if defined (MEM_DEBUG)
#define new DEBUG_NEW
#define delete DEBUG_DELETE
#endif
namespace util
{
tcpsocket::tcpsocket()
: ipsocket()
{
_runmode = -1;
}
tcpsocket::~tcpsocket()
{
close();
}
//client use
int tcpsocket::create(const char* ipaddr, int port)
{
::memset(&inet_address, 0, sizeof(inet_address));
if (ipaddr == 0)
{
inet_address.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
// if (::inet_pton(AF_INET, ipaddr, &inet_address.sin_addr) <= 0)
// throw bad_file(__FILE__, __LINE__, bad_file::bad_sock, strerror(errno));
inet_address.sin_addr.s_addr = inet_addr(ipaddr) ;
}
inet_address.sin_family = AF_INET;
inet_address.sin_port = htons(port);
_runmode = 0;
open(TCP);
connect(&inet_address);
return 0;
}
//server use
int tcpsocket::create(int port)
{
open(TCP);
::memset(&inet_address, 0, sizeof(inet_address));
inet_address.sin_family = AF_INET;
inet_address.sin_addr.s_addr = htonl(INADDR_ANY);
inet_address.sin_port = htons(port);
bind(&inet_address);
accept(&inet_address);
_runmode = 1;
return 0;
}
void tcpsocket::receive(string& msg)
{
int read_count;
int total;
int len;
char buff[4];
if (this == 0)
return;
// Read length.
total = 0;
do
{
read_count = recv(buff + total, 4 - total);
if (read_count < 0)
{
if (errno == EINTR)
continue;
else
throw bad_file(__FILE__, __LINE__, bad_file::bad_sock, strerror(errno));
}
total += read_count;
if (total == 0) // No data available.
throw bad_file(__FILE__, __LINE__, bad_file::bad_sock, strerror(errno));
} while (total < 4);
// Get message length.
len = ((buff[0] & 0xff) << 24) + ((buff[1] & 0xff) << 16) + ((buff[2] & 0xff) << 8) + (buff[3] & 0xff);
if (len <= 0)
throw bad_file(__FILE__, __LINE__, bad_file::bad_sock, strerror(errno));
// Read message.
char* data = new char[len + 1];
total = 0;
do
{
read_count = ipsocket::recv(data + total, len - total);
if (read_count < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
delete[] data;
throw bad_file(__FILE__, __LINE__, bad_file::bad_sock, strerror(errno));
}
}
total += read_count;
} while (total < len);
data[len] = '\0';
msg = data;
delete[] data;
#if defined(DEBUG)
std::cout << "length = " << msg.length() << " [" << msg << "]" << std::endl;
#endif
}
void tcpsocket::send(const string& msg)
{
#if defined(DEBUG)
std::cout << "length = " << msg.length() << " [" << msg << "]" << std::endl;
#endif
if (this == 0)
return;
int write_count;
int len = msg.length();
char* data = new char[len + 4];
// This is length of packet.
data[3] = len & 0xff;
data[2] = (len >> 8) & 0xff;
data[1] = (len >> 16) & 0xff;
data[0] = (len >> 24) & 0xff;
memcpy(data + 4, msg.c_str(), len);
int total = 0;
len += 4;
do
{
write_count = ipsocket::send(data + total, len - total);
if (write_count < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
delete[] data;
throw bad_file(__FILE__, __LINE__, bad_file::bad_sock, strerror(errno));
}
}
total += write_count;
} while (total < len);
delete[] data ;
}
}
三、总结
(1)socket服务器和客户端的代码还可以不断的优化改进以求提高性能和效率。
(2)若有建议,请留言,在此先感谢!