使用Dev-C++實現簡單的客戶端和服務器

先看 效果截圖

在工具菜單下選擇編譯器選項

添加編譯命令-lwsock32 codeblock這些都是這樣的(不設置將會編譯失敗)

 

 

 

首先是初始化 使用Win Socket 必須初始化 原因是 系統有一個Socket池 需要使用Socket則在池中拿一個

具體解釋可以參考

http://blog.sina.com.cn/s/blog_4b146a9c01011ncl.html  

在這一步客戶端和服務器都是一樣的 

    //初始化WSA
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA wsaData;
    if(WSAStartup(sockVersion, &wsaData)!=0)
    {
        return 0;
    }

 之後就是分別介紹

服務器

服務器初始化SOCKECT

    //創建套接字
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(slisten == INVALID_SOCKET)
    {
        printf("socket error !");
        return 0;
    }

使用socket函數進行初始化

這個函數有三個參數:

第一個參數:表示   協議域,又稱爲協議族

  • AF_INET (IPV_4)
  • AF_INET6  (IPV_6)
  • AF_LOCAL(AF_UNIX,本地通信用)
  • AF_ROUTE ( 路由套接字)

還有一些暫時不做介紹(太多了看不完 QAQ)


 第二個參數:信息傳送方式

  • SOCK_STREAM 有保障的(即能保證數據正確傳送到對方)面向連接的SOCKET
  • SOCK_DGRAM 無保障的面向消息的socket 
  • SOCK_RAW 原始套接字(更接近底層的操作)端口對於SOCK_RAW而言沒有任何意義
  • 關於SOCK_RAW具體參考https://www.cnblogs.com/aspirant/p/4084127.htmlhttp://blog.chinaunix.net/uid-29426265-id-4217021.html

  • SOCK_PACKET  (Windows 下似乎是不支持的 這裏不做討論)
  • SOCK_SEQPACKET (與網絡驅動程序直接通信)
  • SOCK_RDM: 提供可靠的數據包連接 (Linux 下似乎不支持 ?)

SOCK_STREAM是基於TCP的,數據傳輸比較有保障。

SOCK_DGRAM是基於UDP的,專門用於局域網,基於廣播SOCK_STREAM 是數據流,一般是tcp/ip協議的編程,SOCK_DGRAM分是數據抱,是udp協議網絡編程


第三個參數 :對應協議

  • IPPROTO_TCP TCP傳輸協議
  • IPPROTO_UDP UDP傳輸協議
  • IPPROTO_SCTP STCP傳輸協議
  • IPPROTO_TIPCTIPC傳輸協議
  • 庫裏面還有很多定義 有機會用用。。

現在已經得到了一個Socket描述符接下來開始使用它 連接服務器或者等待客戶端連接

首先我們看服務器等待客戶端連接

    //綁定IP和端口
    sockaddr_in sin;
    sin.sin_family = AF_INET;		//指定家族 (選擇IP 地址類型) 
    sin.sin_port = htons(8888);		//指定端口號 
    sin.sin_addr.S_un.S_addr = INADDR_ANY; 
								//可以設置爲 
//				#define INADDR_ANY	      (u_long)0				//綁定地址0.0.0.0上的監聽, 能收到任意一塊網卡的連接;
//				#define INADDR_LOOPBACK	 0x7f000001				//綁定地址LOOPBAC, 往往是127.0.0.1, 只能收到127.0.0.1上面的連接請求
//				#define INADDR_BROADCAST	(u_long)0xffffffff	//廣播地址 
    if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)		//進行綁定 
    {
        printf("bind error !");
    }                                                                                                                                                              

    //開始監聽
    if(listen(slisten, 5) == SOCKET_ERROR)	//這個5表示最大連接數
    {
        printf("listen error !");
        return 0;
    }

 接下來就是 監聽等待用戶連接

    //循環接收數據
    SOCKET sClient;
    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);
    char revData[255]; 
    while (true)
    {
        printf("等待連接...\n");
        sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
    /*    if(sClient == INVALID_SOCKET)
        {
            printf("accept error !");
            continue;
        }*/ 
        printf("接受到一個連接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
        
        //接收數據
        int ret = recv(sClient, revData, 255, 0);        
        if(ret > 0)
        {
            revData[ret] = 0x00;
            printf(revData);
            puts(0); 
        }

        //發送數據
        char  sendData[100];
        puts("\n\n你現在可以向客戶端發送信息:");
        gets(sendData); 
        send(sClient, sendData, strlen(sendData), 0);
        closesocket(sClient);
    }
    
    closesocket(slisten);
    WSACleanup();

這個服務器只能一次接受一個用戶的連接 加入多線程 實現多個用戶連接

 這個demo存在bug但是能實現簡單的多用戶連接

#include <stdio.h>
#include <winsock2.h>
#include <malloc.h>
typedef struct ThreadNode
{
	int index;
	HANDLE ThreadId;
	SOCKET Client;
	struct ThreadNode * next;
	ThreadNode()
	{
		index = 0;
		this->next = NULL;		
	}
}hThread;

hThread *clientHeadNote ,*clientEndNote;
hThread * addClient()
{
	hThread * ClientNote = new hThread();
	return ClientNote;	
}

DWORD WINAPI ThreadClient(LPVOID param)
{
	if(clientEndNote == NULL)
	{
		printf("empty Link\n");
		return 0;
	}
	char revData[255]; 
	SOCKET sClient = clientEndNote->Client; 
	while(1)
	{
			//接收數據
	    int ret = recv(sClient, revData, 255, 0);        
	    if(ret > 0)
	    {
	        revData[ret] = 0x00;
	        printf(revData);
	        puts(0); 
	    }
	} 
	closesocket(sClient);
}
int main(int argc, char* argv[])
{
    //初始化WSA
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA wsaData;
    if(WSAStartup(sockVersion, &wsaData)!=0)
    {
        return 0;
    }
	clientEndNote =clientHeadNote = NULL;
    //創建套接字
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    if(slisten == INVALID_SOCKET)
    {
        printf("socket error !");
        return 0;
    }

    //綁定IP和端口
    sockaddr_in sin;
    sin.sin_family = AF_INET;		//指定家族 (選擇IP 地址類型) 
    sin.sin_port = htons(8888);		//指定端口號 
    sin.sin_addr.S_un.S_addr = INADDR_ANY; 
								//可以設置爲 
//				#define INADDR_ANY	      (u_long)0				//綁定地址0.0.0.0上的監聽, 能收到任意一塊網卡的連接;
//				#define INADDR_LOOPBACK	 0x7f000001				//綁定地址LOOPBAC, 往往是127.0.0.1, 只能收到127.0.0.1上面的連接請求
//				#define INADDR_BROADCAST	(u_long)0xffffffff	//廣播地址 
    if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)		//進行綁定 
    {
        printf("bind error !");
    }                                                                                                                                                              

    //開始監聽
    if(listen(slisten, 5) == SOCKET_ERROR)	
    {
        printf("listen error !");
        return 0;
    }

    //循環接收數據

    sockaddr_in remoteAddr;
    int nAddrlen = sizeof(remoteAddr);

    while (true)
    {
        printf("等待連接...\n");
        SOCKET sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
        if(sClient == INVALID_SOCKET)
        {
            printf("accept error !");
            continue;
        }
		 
        printf("接受到一個連接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
        if(clientHeadNote == NULL)
        {
        	clientHeadNote = addClient();
			clientEndNote = clientHeadNote;
        }
        clientEndNote->Client = sClient;
        clientEndNote->ThreadId = CreateThread(NULL, 0, ThreadClient, NULL, 0, NULL);
        
    }
    hThread * p; 
    while(clientHeadNote)//釋放佔用的內存空間 
    {
    	CloseHandle(clientHeadNote->ThreadId);
    	p = clientHeadNote;
    	clientHeadNote = clientHeadNote->next;
    	delete p;
	}
    closesocket(slisten);
    WSACleanup();
    return 0;
}

客戶端和服務器基本一致 

#include <WINSOCK2.H>
#include <STDIO.H>
#pragma  comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
    WORD sockVersion = MAKEWORD(2,2);
    WSADATA data; 
    if(WSAStartup(sockVersion, &data) != 0)
    {
        return 0;
    }

    SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sclient == INVALID_SOCKET)
    {
        printf("無效的 socket !");
        return 0;
    }

    sockaddr_in serAddr;
    serAddr.sin_family = AF_INET;
    serAddr.sin_port = htons(8888);
//    puts("請輸入對方的IP地址");
	char loa[16] = "127.0.0.1";
    serAddr.sin_addr.S_un.S_addr = inet_addr(loa); 
    if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
    {
        printf("連接錯誤 !");
        closesocket(sclient);
        return 0;
    }
    puts("連接成功!!"); 
    puts("你現在可以向服務器發送信息:");
    while(1)
    {
	    
	    char sendData[100];
	    gets(sendData); 
	    send(sclient, sendData, strlen(sendData), 0);
 	}
//    char recData[255];
//    int ret = recv(sclient, recData, 255, 0);
//    if(ret > 0)
//    {
//        recData[ret] = 0x00;
//        printf(recData);
//    }
//   
    closesocket(sclient);
    WSACleanup();
    return 0;
}

 

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