?? chatserver.c
字號:
// 我真誠地保證:
// 由于技術加時間的原因,我雖然沒有完全獨立的把整個程序設計出來,但是通過參考上課筆記和
// 同學的源程序我已經把整個程序的流程和細節都搞清楚,并且最終完成了整個程序。
// 如果在上述過程中,我遇到了什么困難而求教于人,那么,我將在程序實習報告中
// 詳細地列舉我所遇到的問題,以及別人給我的提示。
// 在此,我感謝吳仁海,鮑承會同學對我的啟發和幫助。下面的報告中,我還會具體地提到
// 他們在各個方法對我的幫助。
// 我的程序里中凡是引用到其他程序或文檔之處,
// 例如教材、課堂筆記、網上的源代碼以及其他參考書上的代碼段,
// 我都已經在程序的注釋里很清楚地注明了引用的出處。
// 我從未沒抄襲過別人的程序,也沒有盜用別人的程序,
// 不管是修改式的抄襲還是原封不動的抄襲。
// 我編寫這個程序,從來沒有想過要去破壞或妨礙其他計算機系統的正常運轉。
// 陳友元(01011105)
//文件名稱:chatserver.c
//項目名稱:多線程聊天室
//創建者:陳友元(01011105)
//創建時間:2004-5-31
//最后修改時間:2004-6-3
//功能: 接受客戶端發來的信息
//文件中的函數名稱和簡單功能描述:
//文件中定義的全局變量和簡單功能描述:
//文件中用到的他處定義的全局變量及其出處:
//與其他文件的依賴關系:sock_common.h定義了錯誤信息
/*以下程序為服務器端程序,通過使用多線程(該程序設置為最多5個線程)
來連接客戶端套接字,從而接受客戶端發來的信息,并把信息發送給其他的用戶*/
#include "sock_common.h"
#include <conio.h>
#include <process.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "libcmt.lib")
#define BUFFER_SIZE 500//定義緩沖區大小為500
unsigned __stdcall ProcessThread(void * p);
unsigned long hThreadHandle;
unsigned uThreadID;
static SOCKET chatsock[5];//定義大小為五的套接字樹組用來保存連接到服務器上的客戶端套接字,每一個套接字對應一個聊天室的人。
static char chatip[5][20];//定義5*20的二維數組,用來保存參加聊天的客戶端IP
static int chatcount = 0;//初始聊天人數為0,該變量也用來標室聊天者
int do_something_with(SOCKET NewConnection);
void main(int argc, char *argv[])
{
WSADATA wsaData;
SOCKET ListeningSocket;//監聽套接字
SOCKET NewConnection;//申請連接的套接字
SOCKADDR_IN ServerAddr;//服務器地址
SOCKADDR_IN ClientAddr;//客戶機地址
int ClientAddrLen;//客戶機地址長度
u_short Port = 5150;//默認斷口號為5150
int Ret;//函數調用時返回值
/*****參考上課筆記********/
//初試化低層的Windous Socket DLL
if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
{
printf("WSAStartup failed with error %d\n", Ret);
return;
}
//創建新的socket以監聽客戶端的連接
if ((ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
sockerror("Create socket failed! ");
WSACleanup();
return;
}
ServerAddr.sin_family = AF_INET;/*ADDRESS FAMILY*/
ServerAddr.sin_port = htons(Port);/*PORT NUMBER*/
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);/*INTERNET ADDRESS*/
//把socket和機器上的特定端口連接起來
if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
{
sockerror("Bind failed! ");
closesocket(ListeningSocket);
WSACleanup();
return;
}
//為申請進入的連接建立一個后備日志,然后就可用accept()接受連接了,5為等待連接的最大長度
if (listen(ListeningSocket, 5) == SOCKET_ERROR)
{
sockerror("Liten failed! ");
closesocket(ListeningSocket);
WSACleanup();
return;
}
while(!kbhit())
{
//接受新的連接
ClientAddrLen = sizeof (ClientAddr);
if ((NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen)) == INVALID_SOCKET)
{
sockerror("Accept socket failed! ");
closesocket(ListeningSocket);
WSACleanup();
return;
}
if(chatcount < 5){
chatsock[chatcount] = NewConnection;//將新接收的客戶端套接字保存入服務器端的套接字數組
strcpy(chatip[chatcount], inet_ntoa(ClientAddr.sin_addr));//將客戶端的numbers-and-dots
//格式的IP地址轉換成unsigned long
//并保存
chatcount++;//聊天人數加一
}
else{
printf("Cant chat ,too many people\n");//如果聊天數已經超過5則不予操作,并提示信息
}
//創建并初始化一個線程,該線程和新接收socket連接
hThreadHandle = _beginthreadex(NULL,0,ProcessThread,(void *)&NewConnection,0,&uThreadID);
CloseHandle((HANDLE) hThreadHandle);
}
closesocket(ListeningSocket);//把套接字從擁有對象參考表中取消
WSACleanup();//從底層的Windows Sockets DLL中撤消注冊
}
unsigned __stdcall ProcessThread(void * p)//多線程調用
{
SOCKET connection = *((SOCKET *) p);
do_something_with(connection);//對該套接字進行操作
closesocket(connection);
return 0;
}
int do_something_with(SOCKET NewConnection)
{
SOCKADDR_IN ClientIp;//客戶機地址
char pBuffer[BUFFER_SIZE];
char infomation[BUFFER_SIZE];
char* ipname;//客戶端名稱指針
int len = sizeof(ClientIp), infolen;
int Ret;//返回值
int i;//給其他客戶機發送信息時的循環變量
while(1)
{
Ret = recv(NewConnection,pBuffer,BUFFER_SIZE,0);
if (Ret <= 0)
return Ret;//如果接收失敗則退出
getpeername(NewConnection, &ClientIp, &len);//從客戶端套接字中獲得IP
ipname = inet_ntoa(ClientIp.sin_addr);//將客戶端的numbers-and-dots
//格式的IP地址轉換成unsigned long
//并把指針賦給ipname
sprintf(infomation, "\nmessage from <%s> :\n",ipname);//提示信息來自哪個客戶端
infolen = strlen(infomation);
//在服務器上顯示聊天信息
printf(infomation);//客戶機名
pBuffer[Ret] = '\0';
printf(pBuffer);//聊天記錄
printf("\n-------------------------------------\n");
//向其他客戶機發送聊天記錄,如果是當前說話者的socket則不發送
for(i = 0; i < chatcount; i++){
if(chatsock[i] != NewConnection){
infolen = send(chatsock[i], infomation, infolen, 0);//發送說話客戶機名
Ret = send(chatsock[i], pBuffer, Ret, 0);//發送說話內容
}
}
}
return 1;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -