简单用C#编写socket作为客户端与Linux下C++编写服务器端通信(未完善)

12 篇文章 0 订阅
2 篇文章 0 订阅

废话少说直接上代码:

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);
    }
}

记得要关闭服务器端的防火墙


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值