本文實現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等問題。