跨平臺網絡編程,多個windows客戶端與linux服務端socket通信,epoll實現i/o複用

本文實現Windows客戶端與linux服務器之間的通信,socket網絡編程。

實現多個客戶端連接一個服務器採用的方法不是用while循環,而是更高效的epoll i/o複用,當然你也可以用select 和poll。

windows客戶端(vs2013):

#include <stdio.h>
#include <Windows.h>
#include <sys/types.h> 

#include <io.h>
#include<signal.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[]) 
{

	WSADATA s;
	SOCKET ClientSocket;
	struct sockaddr_in ClientAddr; 
	int ret = 0;
	char SendBuffer[MAX_PATH]; 
	/*socket編程要調用各種socket函數,但是需要庫Ws2_32.lib和頭文件Winsock2.h,這裏的WSAStartup就是爲了向操作系統說明,我們要用哪個庫文件*/
	
	if (WSAStartup(MAKEWORD(2, 2), &s) != 0) 
	{
		printf("Init Windows Socket Failed! Error: %d\n", GetLastError());
		getchar();
		return -1;
	}
	
	ClientSocket = socket(AF_INET, SOCK_STREAM, 0); //創建套接字
	if (ClientSocket == INVALID_SOCKET)
	{
		printf("Create Socket Failed! Error: %d\n", GetLastError());
		getchar();
		return -1;
	}

	ClientAddr.sin_family = AF_INET;
	ClientAddr.sin_addr.s_addr = inet_addr("192.168.80.130"); //這個ip爲linux虛擬機的ip
	ClientAddr.sin_port = htons(5000); 
	memset(ClientAddr.sin_zero, 0X00, 8); 

	ret = connect(ClientSocket,(struct sockaddr*)&ClientAddr,sizeof(ClientAddr));//主動發起連接
	if (ret == SOCKET_ERROR)
	{
		printf("Socket Connect Failed! Error:%d\n", GetLastError());
		getchar();
		return -1;
	}
	else
	{
		printf("Socket Connect Succeed!\n");
	}
	
	while (1)
	{
		printf("Input Data: ");
		scanf("%s", &SendBuffer);
		ret = send(ClientSocket, SendBuffer, (int)strlen(SendBuffer), 0);
		if (ret == SOCKET_ERROR)
		{
			printf("Send Information Failed! Error:%d\n", GetLastError());
			getchar();
			break;
		}	
	}
		
	closesocket(ClientSocket);		
	WSACleanup();
	getchar();
	return 0;
}

linux服務端:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
//#include<netinet.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<sys/epoll.h>
void setnonblocking(int sockfd)//設置非阻塞線程
{
	fcntl(sockfd,F_SETFL,fcntl(sockfd,F_GETFD,0)|O_NONBLOCK);
	
}
void addfd(int epollfd,int fd,bool enable_et)//將事件fd添加到監聽隊列
{
	struct epoll_event ev;
	ev.data.fd =fd;
	ev.events =EPOLLIN;
	if(enable_et)
	ev.events =EPOLLIN |EPOLLET;
	epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
	setnonblocking(fd);

}
int main()
{
    
    int listenfd =socket(AF_INET,SOCK_STREAM,0);
    if(listenfd<0)
    {
        printf("listenfd error\n");
        exit(0);
    }
    
    
    struct sockaddr_in servaddr;
    servaddr.sin_family =AF_INET;
    servaddr.sin_port =htons(5000);
    servaddr.sin_addr.s_addr =htonl(INADDR_ANY);//htonl從主機字節序轉換成網絡字節序

    bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    
    printf("start wait accept...\n");
    if(listen(listenfd,5))
    {
        printf("listening...");
    }
    struct sockaddr_in peeraddr;
    socklen_t peerlen =sizeof(peeraddr);
    int conn;
	int n =0;
	int epfd =epoll_create(50);

	
	struct epoll_event events[50];
	addfd(epfd,listenfd,true);
	while(1)
	{
		int epoll_events_count =epoll_wait(epfd,events,50,-1);
		if(epoll_events_count<0)break;

		for(n=0;n<epoll_events_count;++n)
		{
			int sockfd =events[n].data.fd;

		if(sockfd==listenfd)//如果是監聽fd,則表示有新的客戶端請求鏈接
		{
			int client =accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen);
			if(client<0)
			{
				printf("accept...\n");
				continue;
			}
			write(client,"ok",2);
			printf("cli =%d\n",client);
			setnonblocking(client);
			addfd(epfd,client,true);
		}
			else//否則監聽隊列的fd有事情發生需要處理
			{
				
				char buffer[100]="";
				int sockfd_r=events[n].data.fd;
				write(sockfd_r,"ok",2);
				read(sockfd_r,buffer,125);
				printf("%s\n",buffer);
				
			}
		}
	}


    return 0;
}

運行結果:

如果出現無法連接請檢查ip和port字節序的轉換問題。htons和htonl等問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章