首页 » 技术分享 » TCP通讯:客户端和服务端

TCP通讯:客户端和服务端

 

客户端:

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <iostream>

using namespace std;

int main(int argc, char **argv)
{
	int iRet = 0;
	int iSocket = -1;
	int iClientFd = -1;
	int iTcpPort = 0;
	char *pcTcpAddr = NULL;
	static unsigned int suiNo = 0; 
	socklen_t stCliAddrLen = 0;
	struct sockaddr_in stCliAddr;
	fd_set stFdSet, stReadFdSet;
	char *arrDataBuff[1024000] = {0};
	struct timeval stTv;
	
	if(3 != argc){
		cout << "Usage :\n  cli <ip_addr> <port>" << endl;
		return -1;
	}
	else{
		iTcpPort = atoi(argv[2]);
		pcTcpAddr = argv[1];
	}
	
	iSocket = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == iSocket){
		cout << "Socket error!" << endl;
		return -1;
	}
	
	bool bReuseaddr = true;
	setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&bReuseaddr, sizeof(bool));
	setsockopt(iSocket,IPPROTO_TCP, TCP_NODELAY, (char *)&bReuseaddr, sizeof(bool));	
	
	stTv.tv_sec = 2;
	stTv.tv_usec = 0;
	setsockopt(iSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&stTv, sizeof(stTv));
	
	struct linger stLinger;
	stLinger.l_onoff = 1;
	stLinger.l_linger = 0;
	setsockopt(iSocket, SOL_SOCKET, SO_LINGER, (char *)&stLinger, sizeof(struct linger));
	
	stCliAddr.sin_family = AF_INET;
	stCliAddr.sin_port = htons(iTcpPort);
	stCliAddr.sin_addr.s_addr = inet_addr(pcTcpAddr);
	if(0 != connect(iSocket, (sockaddr *)&stCliAddr, sizeof(stCliAddr))){
		cout << "Connect error!" << endl;
		return -1;
	}
	
	FD_ZERO(&stFdSet);
	FD_SET(iSocket, &stFdSet);	

	while(true){
		memset(arrDataBuff, 0x23, sizeof(arrDataBuff));
		iRet = write(iSocket, arrDataBuff, sizeof(arrDataBuff));
		if(iRet < 0){
			cout << "Write error!" << endl;
		}
		#if 0
		stTv.tv_sec = 5;
		stTv.tv_usec = 0;	
		stReadFdSet = stFdSet;	
		iRet = select(iSocket+1, &stReadFdSet, NULL, NULL, &stTv);
		cout << "iRet = " << iRet << endl;
		if(0 >= iRet){
			continue;
		} 
	
		memset(arrDataBuff, 0x00, sizeof(arrDataBuff));
		iRet = read(iSocket, arrDataBuff, sizeof(arrDataBuff));		
		if(0 > iRet){
			cout << "Read error!" << endl;
			close(iSocket);
		}
		else if(0 == iRet){
			
		}
		else{			
			iRet = write(iSocket, arrDataBuff, sizeof(arrDataBuff));
			if(iRet < 0){
				cout << "Write error!" << endl;
			}
		}	
		#endif
	}
	
	getchar();
	close(iSocket);
	
	return 0;	
}

服务端:

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <iostream>

using namespace std;

int main(int argc, char **argv)
{
	int i = 0;
	int iRet = 0;
	int inRead = 0;
	int iCount = 0;
	int iOpts = 0;
	int iSocket = -1;
	int iEpollFd = -1;
	int iClientFd = -1;
	int iTcpSvrPort = 0;
	char chRcvBuff[1024] = {0};
	socklen_t stCliAddrLen = 0;
	struct epoll_event stEvent;
	struct epoll_event arrEv[1024];
	struct sockaddr_in stSvrAddr, stCliAddr;
	
	if(2 == argc){
		iTcpSvrPort = atoi(argv[1]);
		cout << "TCP Server Port = " << iTcpSvrPort << endl;
	}
	
	bzero(&stSvrAddr, sizeof(stSvrAddr));
	bzero(&stCliAddr, sizeof(stCliAddr));
	//创建本地SOCKET
	iSocket = socket(AF_INET, SOCK_STREAM, 0);
	if(0 >= iSocket){
		cout << "Get socket handler error!" << endl;
		return -1;
	}
	
	//绑定监听端口
	stSvrAddr.sin_family = AF_INET;
	if(0 == iTcpSvrPort){
		stSvrAddr.sin_port = htons(20015);
	}
	else{
		stSvrAddr.sin_port = htons(iTcpSvrPort);
	}
	
	//绑定所有地址端口
	stSvrAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	//设置描述符属性
	iOpts = fcntl(iSocket, F_GETFL);
	if(iOpts < 0){
		cout << "Opts getfl error!" << endl;
		return -1;
	}
	
	iOpts = iOpts | O_NONBLOCK;
	if(fcntl(iSocket, F_SETFL, iOpts) < 0){
		cout << "Opts setfl error!" << endl;
		return -1;
	}
	
	//让close立即返回,避免产生TIME_WAITE状态
	struct linger stLinger;
	stLinger.l_onoff = 1;	//允许等待
	stLinger.l_linger = 0;	//等待时间设置为0,即不等待
	iRet = setsockopt(iSocket, SOL_SOCKET, SO_LINGER, (char *)&stLinger, sizeof(struct linger));
	if(0 > iRet){
		cout << "Setsockopt error!" << endl;
	}
	
	iRet = bind(iSocket, (struct sockaddr *)&stSvrAddr, sizeof(struct sockaddr));
	if(0 != iRet){
		close(iSocket);
		return -1;
	}
	
	iRet = listen(iSocket, 255);
	if(0 != iRet){
		close(iSocket);
		return -1;
	}
	
	/*套接字监控*/
	//创建epoll监听fd
	iEpollFd = epoll_create(1024);	//监听最大数量
	if(0 >= iEpollFd){
		cout << "Epoll creat error!" << endl;
		return -1;
	}
	
	stEvent.data.fd = iSocket;
	//stEvent.events = EPOLLIN | EPOLLET;	//边缘触发
    stEvent.events = EPOLLIN;
	epoll_ctl(iEpollFd, EPOLL_CTL_ADD, iSocket, &stEvent);
	
	/*数据接收*/
	while(true){
		memset(arrEv, 0x00, sizeof(arrEv));
		iCount = epoll_wait(iEpollFd, arrEv, 16, 1);
		for(i = 0; i < iCount; i++){
			//在iSocket上有事件发生,说明有新客户端连接
			if(arrEv[i].data.fd == iSocket){
				stCliAddrLen = sizeof(struct sockaddr);
				iClientFd = accept(iSocket, (struct sockaddr *)&stCliAddr, &stCliAddrLen);
				if(0 > iClientFd){
					cout << "Accept client error!" << endl;
				}
				
				/*把客户端加入到EPOLL中*/
				//设置描述符属性
				iOpts = fcntl(iClientFd, F_GETFL);
				if(iOpts < 0){
					cout << "[Client]Opts getfl error!" << endl;
					return -1;
				}
				
				iOpts = iOpts | O_NONBLOCK;
				if(fcntl(iClientFd, F_SETFL, iOpts) < 0){
					cout << "[Client]Opts setfl error!" << endl;
					return -1;
				}
				
				stEvent.data.fd = iClientFd;
				//stEvent.events = EPOLLIN | EPOLLET; //EPOLLET边沿触发,事件未处理一直触发
				stEvent.events = EPOLLIN;	//EPOLLIN有可读数据
				epoll_ctl(iEpollFd, EPOLL_CTL_ADD, iClientFd, &stEvent);
			}
			else if(arrEv[i].events & EPOLLIN){
				memset(chRcvBuff, 0x00, sizeof(chRcvBuff));
				inRead = read(arrEv[i].data.fd, chRcvBuff, sizeof(chRcvBuff));
				if(errno == EINTR){
					cout << "Error : EINTR" << endl;
				}
				
				if(inRead < 0){
					cout << "Read error" << endl;
					//删除EPOLL监控事件
					stEvent.data.fd = arrEv[i].data.fd;
					stEvent.events = EPOLLIN;
					epoll_ctl(iEpollFd, EPOLL_CTL_DEL, arrEv[i].data.fd, &stEvent);
					if (-1 != arrEv[i].data.fd){
						close(arrEv[i].data.fd);
					}
				}
				else if(0 == inRead){
					
				}
				else{
					iRet = write(arrEv[i].data.fd, chRcvBuff, inRead);
					if(iRet < 0){
						cout << "Send data error!" << endl;
					}
					
				}
			}
		}
	}	
	
	return 0;
}

转载自原文链接, 如需删除请联系管理员。

原文链接:TCP通讯:客户端和服务端,转载请注明来源!

0