1. 程式人生 > >linux下c/c++例項之十socket伺服器例項

linux下c/c++例項之十socket伺服器例項

一、簡介


二、詳解

(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伺服器:
s
ocket_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客戶端:
s
ocket_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 [email protected] $(LDFLAGS) socket_client.cpp $(LIBS)
socket_server: socket_server.cpp
	$(CC) -o [email protected] $(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)若有建議,請留言,在此先感謝!

相關推薦

linuxc/c++例項socket伺服器例項

一、簡介 二、詳解 (1)多執行緒併發伺服器server.c //使用pthread執行緒庫 #include <stdio.h> #include <string.h> #include <u

linuxc/c++例項socket簡單應用

一、簡介       通過socket掃描本機開啟的tcp埠號,模擬使用者名稱、密碼登入伺服器的過程、socket檔案傳輸及模仿http伺服器。 二、詳解 1、Linux下tcp埠掃描 (1)scanport.c: /

linux用多執行緒實現socket伺服器和客戶端的非同步通訊

前面介紹了用select函式來實現socket的非同步收發資料,但是select函式也有一些缺陷,要使socket能持續地通訊,select必須不停地檢測,這樣程序就會一直阻塞在這裡,限制了功能的擴充套件,這裡我們用多執行緒的方式,另建立兩個執行緒用來發送/接收

linuxc/c++例項c實現的bt軟體下載(記錄)

一、簡介        可能許多人使用過位元彗星(BitComet)、位元精靈(BitSpirit)、迅雷下載過自己喜歡的影片、電視劇、網路遊戲;還有很多人使用過PPLive、PPStream、沸點、QQ直播等免費的網路電視直播軟體線上觀看自己喜歡的影片。所有這些軟體都採

Linux C編程九(1) libevent基本概念

通信 == socket通信 驅動 1.4 event http linu make 一、libevent是幹什麽的 1. 開源的庫, 提高開發效率 封裝了socket通信 封裝了IO多路轉接 2. 精簡, 專註於網絡, 性能高 3

LinuxC獲取當前時間

time() 使用 ble timespec -1 ber 區間 本地 指向 Linux下用C獲取當前時間,具體如下: 代碼(可以把clock_gettime換成time(NULL)) ? 1 2 3 4 5 6 7 8 9 10 void getN

C#設計模式二代理模式(Proxy Pattern)【結構型】

ride col 安全 .html 使用權 防火墻 一對多 tro 橋接 原文:C#設計模式之十二代理模式(Proxy Pattern)【結構型】一、引言 今天我們要講【結構型】設計模式的第七個模式,也是“結構型”設計模式中的最後一個模式,該模式是【代理模式】,英文名稱

C#設計模式七中介者模式(Mediator Pattern)【行為型】

[] 過多 深入 理解 申請 代碼實現 控制 name 缺點 原文:C#設計模式之十七中介者模式(Mediator Pattern)【行為型】一、引言 今天我們開始講“行為型”設計模式的第五個模式,該模式是【中介者模式】,英文名稱是:Mediator Pattern。還

C#設計模式六觀察者模式(Observer Pattern)【行為型】

ngx 現實生活 松耦合 mon html 機制 account current 很好 原文:C#設計模式之十六觀察者模式(Observer Pattern)【行為型】一、引言 今天是2017年11月份的最後一天,也就是2017年11月30日,利用今天再寫一個模式,爭取

C#設計模式一享元模式(Flyweight Pattern)【結構型】

eal 客戶 來看 滿足 對象狀態 英文 輔助 3.3 fig 原文:C#設計模式之十一享元模式(Flyweight Pattern)【結構型】一、引言 今天我們要講【結構型】設計模式的第六個模式,該模式是【享元模式】,英文名稱是:Flyweight Pattern。還

C#設計模式九策略模式(Stragety Pattern)【行為型】

多條件 第一次 必須 this 數據傳遞 名稱 面向 div 想要 原文:C#設計模式之十九策略模式(Stragety Pattern)【行為型】一、引言 今天我們開始講“行為型”設計模式的第七個模式,該模式是【策略模式】,英文名稱是:Stragety Pattern。

LinuxC語言開發

xuni autoconf htm 參加 eve http 學習資料 inux c語言開發 工具 學會使用vim/emacs,vim/emacs是linux下最常用的源碼編輯具,不光要學會用它們編輯源碼,還要學會用它們進行查找、定位、替換等。 學會makefile文件的編

linux利用CC++ 語言調用需要root權限的函數

編譯程序 註意 步驟 oot 登錄 調用 get bsp 屬於 1、setuid法(1)登錄root用戶,將程序設置成root:root所有者(等價於:登錄root用戶編譯程序)。也可直接將普通用戶加入root組中,那麽編譯程序不用來回切換用戶。(2)登錄root用戶設置程

linux編譯c語言教程

準備工作 - Linux系統 - 懂得Linux系統下編輯器vim/vi軟體的使用 - 懂得簡易的c語言程式設計(初次學習的同學可以直接複製文章末尾的原始碼) 總結一下:有Linux系統,會使用Linux系統下的文字編輯器,有一點c語言基礎即可。 建立c語言檔案並編譯

linux 執行C程式

#include<stdio.h> int main(){ int a=100,b=25; if(a>b) printf(" The high value is %d\n",a); else printf(" Th

C#資料結構單鏈表(LinkList)例項詳解

本文例項講述了C#資料結構之單鏈表(LinkList)實現方法。分享給大家供大家參考,具體如下: 這裡我們來看下“單鏈表(LinkList)”。在上一篇《C#資料結構之順序表(SeqList)例項詳解》的最後,我們指出了:順序表要求開闢一組連續的記憶體空間,而且插入/刪除元素時,為了保證元素的順序

LinuxC語言函式perror

perror的函式原型為`void perror(const char *s)` 這個函式會先輸出你傳給他的實參 s 所指的字串,後面再加上錯誤原因字串。此錯誤原因依照全域性變數errno 的值來決定要輸出的字串。 在庫函式中有個errno變數,每個errno值對應著以字串表示的錯誤型別。當

單目跟蹤位姿產品研發(二)----在linuxc++工程打包成動態庫so檔案API

       單目跟蹤位姿專案由對方公司提供應用場景,我方研發核心演算法,通過c++實現功能,然後對方公司通過java\js來開發炫酷的介面,共同合作完成,最終對方公司負責銷售推廣,推向市場。因此,涉及到java介面呼叫c++核心程式碼的問題。 現記錄

LINUX編譯c++11的程式碼

 C++11,(即ISO/IEC 14882:2011),是目前的C++程式語言的最新正式標準。它取代了第二版標準(第一版公開於1998年,第二版於2003年更新,分別通稱C++98以及C++03,兩者差異很小)。新的標準包含核心語言的新機能,而且擴充套件C++標準程式庫。C++11新標準

linuxc語言系統函式呼叫

目錄 4.linux下的系統函式的使用 c語言 4.1數學函式的使用 1pow函式 2.exp函式 3.log函式 4.rand()隨機數函式 4.2字元函式的使用 4.3系統時間與日期函式的使用 系統時間 時間間隔 4.4環境控制函式 &nb