废话少说直接上代码:
C#客户端代码:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;//类Thread就在此空间内,可以调用sleep函数
using System.Linq;
using System.Text;
namespace Heart
{
class Program
{
private static Int32 port=3333;
static void Main(string[] args)
{
byte[] data=new byte[1024];
string str = "Hello! Welcome to C# World";
Socket newclient=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
Console.Write("Please input the server ip:");
string ipadd=Console.ReadLine();
IPEndPoint ie=new IPEndPoint(IPAddress.Parse(ipadd),port);//服务器端的IP和端口
try
{
newclient.Connect(ie);
}
catch(SocketException e)
{
Console.WriteLine("Unable to connect to server");
Console.WriteLine(e.ToString());
return;
}
for(;;)
{.//循环发送和接收
Thread.Sleep(5000);//睡眠5秒钟
data=Encoding.ASCII.GetBytes(str);
newclient.Send(data, data.Length, SocketFlags.None);//发送信息
int recv = newclient.Receive(data);
string stringdata = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine("received:" + stringdata);
}
}
}
}
服务器端代码:
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<sys/socket.h>
#include<sys/epoll.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<errno.h>
#include<unistd.h>
#include<string.h>
#include<netinet/tcp.h>
#define SERVER_PORT 3333
#define LENGTH_OF_LISTEN_QUEUE 20
#define MAXBUF 100
using namespace std;
int EstablishServer(struct sockaddr_in * addr,socklen_t addrLen,int port);
void * HeartService(void * arg);
void setnonblocking(int sock);
int main()
{
struct sockaddr_in server_addr,client_addr;
int serverFd,clientFd;
socklen_t clientLen=sizeof(struct sockaddr);
//建立socket连接
serverFd=EstablishServer(&server_addr,sizeof(server_addr),SERVER_PORT);
if(serverFd==-1)
{
cout<<"serverFd create failed!"<<endl;
exit(1);
}
for(;;)
{
//等待连接的请求
if((clientFd=accept(serverFd,(struct sockaddr *)&client_addr,&clientLen))<0)
{
perror("accept wrong !:");
exit(1);
}
cout<<"----------------------------------------------------------------"<<endl;
printf("accept from %s:%d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);
pthread_t clientTid;
int pthrst=pthread_create(&clientTid,NULL,HeartService,(void *)&clientFd);
if(pthrst!=0)
{
perror("pthread_create wrong ! :");
}
}
return 0;
}
//建立服务端socket的通信,绑定端口
int EstablishServer(struct sockaddr_in * addr,socklen_t addrLen,int port)
{
int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd<0)
{
perror("listenfd socket error");
return -1;
}
bzero(addr,addrLen);
addr->sin_family=AF_INET;
addr->sin_addr.s_addr=htonl(INADDR_ANY);
addr->sin_port=htons(port);
if(bind(listenfd,(struct sockaddr *)addr,addrLen)<0)
{
perror("bind error");
return -1;
}
if(listen(listenfd,LENGTH_OF_LISTEN_QUEUE)<0)
{
perror("listen error");
return -1;
}
return listenfd;
}
//心跳机制线程
void *HeartService(void * arg)
{
//获得自身的线程号
pthread_t tid=pthread_self();
//获得传送过来的clientFd
int clientFd=*(int *)arg;
cout<<"New thread create,the tid is "<<tid<<" the clientFd is "<<clientFd<<endl;
int sockfd;//用于获取epoll函数的fd值
char buf[MAXBUF];
int epfd,nfds,n,m,count=0;
struct epoll_event ev,events[20];//声明epoll_event结构体的变量,ev用于注册事件,events数组用于回传要处理的事件
int keepAlive=1;//开启keepalive属性
int keepIdle=5;//如该连接在5秒内没有任何数据往来,则进行探测
int keepInterval=2;//探测时发包的时间间隔为2秒
int keepCount=3;//探测尝试的次数。如果第1次探测包就收到响应了,则后2次的不再发送
setsockopt(clientFd,SOL_SOCKET,SO_KEEPALIVE,(void *)&keepAlive,sizeof(keepAlive));
setsockopt(clientFd,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle));
setsockopt(clientFd,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval));
setsockopt(clientFd,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount));
//把客户端的socket设置为非阻塞方式
setnonblocking(clientFd);
epfd=epoll_create(256);//生成epoll专用的文件描述符,指定生成描述符的最大范围为256
ev.data.fd=clientFd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,clientFd,&ev);
for(;;)
{
nfds=epoll_wait(epfd,events,20,-1);
cout<<"the tid is "<<tid<<" the clientFd is "<<clientFd<<" the count is "<<++count<<endl;
for(int i=0;i<nfds;++i)
{
if(events[i].events&EPOLLIN)
{
if((sockfd=events[i].data.fd)<0)
{
cout<<"It is recevied continue!"<<endl;
continue;//因为下面设置了,所以这里考虑了
}
if((n=recv(sockfd,buf,MAXBUF,0))<0)
{
if(errno==ECONNRESET)//表示连接被重置了,已经无效了,关闭它,删除它
{
printf("It is ECONNRESET:%s\n",strerror(ECONNRESET));
epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);//可以把这个sockfd从epfd队列中删除了
}
else if(errno==ETIMEDOUT)
{
cout<<"Ha Ha you want ETIMEDOUT"<<endl;
}
else
cout<<"read error!"<<endl; //其他错误
epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
return 0;
}
else if(n==0)//有读事件触发,但是read返回0,所以是对面已经关闭sockfd了
{
cout<<"n=0 ,sockfd is "<<sockfd<<" and tid is "<<tid<<endl;
epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
close(sockfd);
}
else
{
buf[n]='\0';
cout<<"received:"<<buf<<" and sockfd is "<<sockfd<<endl;
ev.data.fd=sockfd;
ev.events=EPOLLOUT|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
}
}
else if(events[i].events&EPOLLOUT)
{
sockfd=events[i].data.fd;
m=strlen(buf);
cout<<"m is "<<m<<endl;
if(write(sockfd,buf,m)<0)
{
cout<<"write wrong ! and sockfd is:"<<sockfd<<endl;
}
else
{
cout<<"send success and buf is "<<buf<<endl;
}
ev.data.fd=sockfd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);//修改sockfd上要处理的事件为EPOLLIN,下次监听读事件
}
}
}
}
void setnonblocking(int sock)
{
int opts;
opts=fcntl(sock,F_GETFL);//把sock的属性查询出来,存到opts中
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts=opts|O_NONBLOCK;//把opts中的某一位O_NONBLOCK置为生效
if(fcntl(sock,F_SETFL,opts)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
记得要关闭服务器端的防火墙