亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

socket多人聊天程序C語言版(二)

 更新時間:2021年06月30日 15:20:37   作者:_acme_  
這篇文章主要為大家詳細介紹了socket多人聊天程序C語言版第二篇,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

socket多人聊天程序C語言版(一)地址

1V1實現(xiàn)了,1V多也就容易了。不過相對于1V1的程序,我經過大改,采用鏈表來動態(tài)管理。這樣效率真的提升不少,至少CPU使用率穩(wěn)穩(wěn)的在20以下,不會飆到100了。用C語言寫這個還是挺費時間的,因為什么功能函數(shù)都要自己寫,不像C++有STL庫可以用,MFC寫就更簡單了,接下來我還會更新MFC版本的多人聊天程序。好了,廢話少說,進入主題。

這個程序要解決的問題如下:

1.CPU使用率飆升問題 –>用鏈表動態(tài)管理

2.用戶自定義聊天,就是想跟誰聊跟誰聊 –> _Client結構體中新增一個ChatName字段,用來表示要和誰聊天,這個字段很重要,因為server轉發(fā)消息的時候就是按照這個字段來轉發(fā)的。

3.中途換人聊天,就是聊著聊著,想和別人聊,而且自己還一樣能接收到其它人發(fā)的消息 –> 這個就要小改客戶端的代碼了,可以在發(fā)送聊天消息之前插入一段代碼,用來切換聊天用戶。具體做法就是,用getch()函數(shù)讀取ESC鍵,如果用戶按了這個鍵,則表示想切換用戶,然后會輸出一行提示,請輸入chat name,就是想要和誰聊天的名字,發(fā)送這個名字過去之前要加一個標識符,表示這個消息是切換聊天用戶消息。然后server接收到這個消息后會判斷第一個字符是不是標識符,第二個字符不能是標識符,則根據這個name來查找當前在線的用戶,然后修改想切換聊天用戶的ChatName為name這個用戶。(可能有點繞,不懂的看代碼就清晰易懂了~)

4.下線后提醒對方 –> 還是老套路,只要send對方不通就當對方下線了。

編寫環(huán)境:WIN10,VS2015

效果圖:

為了方便就不用虛擬機演示了,但是在虛擬機是肯定可以的,應該說只要是局域網,能互相ping通就可以使用這個程序。

Server code:

鏈表頭文件:

#ifndef _CLIENT_LINK_LIST_H_
#define _CLIENT_LINK_LIST_H_

#include <WinSock2.h>

#include <stdio.h>

//客戶端信息結構體
typedef struct _Client
{
 SOCKET sClient;   //客戶端套接字
 char buf[128];   //數(shù)據緩沖區(qū)
 char userName[16];  //客戶端用戶名
 char IP[20];   //客戶端IP
 unsigned short Port; //客戶端端口
 UINT_PTR flag;   //標記客戶端,用來區(qū)分不同的客戶端
 char ChatName[16];  //指定要和哪個客戶端聊天
 _Client* next;   //指向下一個結點
}Client, *pClient;

/* * function 初始化鏈表 * return 無返回值 */
void Init();

/* * function 獲取頭節(jié)點 * return 返回頭節(jié)點 */
pClient GetHeadNode();

/* * function 添加一個客戶端 * param client表示一個客戶端對象 * return 無返回值 */
void AddClient(pClient client);

/* * function 刪除一個客戶端 * param flag標識一個客戶端對象 * return 返回true表示刪除成功,false表示失敗 */
bool RemoveClient(UINT_PTR flag);

/* * function 根據name查找指定客戶端 * param name是指定客戶端的用戶名 * return 返回一個client表示查找成功,返回INVALID_SOCKET表示無此用戶 */
SOCKET FindClient(char* name);

/* * function 根據SOCKET查找指定客戶端 * param client是指定客戶端的套接字 * return 返回一個pClient表示查找成功,返回NULL表示無此用戶 */
pClient FindClient(SOCKET client);

/* * function 計算客戶端連接數(shù) * param client表示一個客戶端對象 * return 返回連接數(shù) */
int CountCon();

/* * function 清空鏈表 * return 無返回值 */
void ClearClient();

/* * function 檢查連接狀態(tài)并關閉一個連接 * return 返回值 */
void CheckConnection();

/* * function 指定發(fā)送給哪個客戶端 * param FromName,發(fā)信人 * param ToName, 收信人 * param data, 發(fā)送的消息 */
void SendData(char* FromName, char* ToName, char* data);


#endif //_CLIENT_LINK_LIST_H_

鏈表cpp文件:

#include "ClientLinkList.h"

pClient head = (pClient)malloc(sizeof(_Client)); //創(chuàng)建一個頭結點

/* * function 初始化鏈表 * return 無返回值 */
void Init()
{
 head->next = NULL;
}

/* * function 獲取頭節(jié)點 * return 返回頭節(jié)點 */
pClient GetHeadNode()
{
 return head;
}

/* * function 添加一個客戶端 * param client表示一個客戶端對象 * return 無返回值 */
void AddClient(pClient client)
{
 client->next = head->next; //比如:head->1->2,然后添加一個3進來后是
 head->next = client;  //3->1->2,head->3->1->2
}

/* * function 刪除一個客戶端 * param flag標識一個客戶端對象 * return 返回true表示刪除成功,false表示失敗 */
bool RemoveClient(UINT_PTR flag)
{
 //從頭遍歷,一個個比較
 pClient pCur = head->next;//pCur指向第一個結點
 pClient pPre = head;  //pPre指向head 
 while (pCur)
 {
  // head->1->2->3->4,要刪除2,則直接讓1->3
  if (pCur->flag == flag)
  {
   pPre->next = pCur->next;
   closesocket(pCur->sClient); //關閉套接字
   free(pCur); //釋放該結點
   return true;
  }
  pPre = pCur;
  pCur = pCur->next;
 }
 return false;
}

/* * function 查找指定客戶端 * param name是指定客戶端的用戶名 * return 返回socket表示查找成功,返回INVALID_SOCKET表示無此用戶 */
SOCKET FindClient(char* name)
{
 //從頭遍歷,一個個比較
 pClient pCur = head;
 while (pCur = pCur->next)
 {
  if (strcmp(pCur->userName, name) == 0)
   return pCur->sClient;
 }
 return INVALID_SOCKET;
}

/* * function 根據SOCKET查找指定客戶端 * param client是指定客戶端的套接字 * return 返回一個pClient表示查找成功,返回NULL表示無此用戶 */
pClient FindClient(SOCKET client)
{
 //從頭遍歷,一個個比較
 pClient pCur = head;
 while (pCur = pCur->next)
 {
  if (pCur->sClient == client)
   return pCur;
 }
 return NULL;
}

/* * function 計算客戶端連接數(shù) * param client表示一個客戶端對象 * return 返回連接數(shù) */
int CountCon()
{
 int iCount = 0;
 pClient pCur = head;
 while (pCur = pCur->next)
  iCount++;
 return iCount;
}

/* * function 清空鏈表 * return 無返回值 */
void ClearClient()
{
 pClient pCur = head->next;
 pClient pPre = head;
 while (pCur)
 {
  //head->1->2->3->4,先刪除1,head->2,然后free 1
  pClient p = pCur;
  pPre->next = p->next;
  free(p);
  pCur = pPre->next;
 }
}

/* * function 檢查連接狀態(tài)并關閉一個連接 * return 返回值 */
void CheckConnection()
{
 pClient pclient = GetHeadNode();
 while (pclient = pclient->next)
 {
  if (send(pclient->sClient, "", sizeof(""), 0) == SOCKET_ERROR)
  {
   if (pclient->sClient != 0)
   {
    printf("Disconnect from IP: %s,UserName: %s\n", pclient->IP, pclient->userName);
    char error[128] = { 0 }; //發(fā)送下線消息給發(fā)消息的人
    sprintf(error, "The %s was downline.\n", pclient->userName);
    send(FindClient(pclient->ChatName), error, sizeof(error), 0);
    closesocket(pclient->sClient); //這里簡單的判斷:若發(fā)送消息失敗,則認為連接中斷(其原因有多種),關閉該套接字
    RemoveClient(pclient->flag);
    break;
   }
  }
 }
}

/* * function 指定發(fā)送給哪個客戶端 * param FromName,發(fā)信人 * param ToName, 收信人 * param data, 發(fā)送的消息 */
void SendData(char* FromName, char* ToName, char* data)
{
 SOCKET client = FindClient(ToName); //查找是否有此用戶
 char error[128] = { 0 };
 int ret = 0;
 if (client != INVALID_SOCKET && strlen(data) != 0)
 {
  char buf[128] = { 0 };
  sprintf(buf, "%s: %s", FromName, data); //添加發(fā)送消息的用戶名
  ret = send(client, buf, sizeof(buf), 0);
 }
 else//發(fā)送錯誤消息給發(fā)消息的人
 {
  if(client == INVALID_SOCKET)
   sprintf(error, "The %s was downline.\n", ToName);
  else
   sprintf(error, "Send to %s message not allow empty, Please try again!\n", ToName);
  send(FindClient(FromName), error, sizeof(error), 0);
 }
 if (ret == SOCKET_ERROR)//發(fā)送下線消息給發(fā)消息的人
 {
  sprintf(error, "The %s was downline.\n", ToName);
  send(FindClient(FromName), error, sizeof(error), 0);
 }

}

server cpp:

/*

#include <WinSock2.h>
#include <process.h>
#include <stdlib.h>
#include "ClientLinkList.h"
#pragma comment(lib,"ws2_32.lib")


SOCKET g_ServerSocket = INVALID_SOCKET;  //服務端套接字
SOCKADDR_IN g_ClientAddr = { 0 };   //客戶端地址
int g_iClientAddrLen = sizeof(g_ClientAddr);

typedef struct _Send
{
 char FromName[16];
 char ToName[16];
 char data[128];
}Send,*pSend;

//發(fā)送數(shù)據線程
unsigned __stdcall ThreadSend(void* param)
{
 pSend psend = (pSend)param; //轉換為Send類型
 SendData(psend->FromName, psend->ToName, psend->data); //發(fā)送數(shù)據
 return 0;
}

//接受數(shù)據
unsigned __stdcall ThreadRecv(void* param)
{
 int ret = 0;
 while (1)
 {
  pClient pclient = (pClient)param;
  if (!pclient)
   return 1;
  ret = recv(pclient->sClient, pclient->buf, sizeof(pclient->buf), 0);
  if (ret == SOCKET_ERROR)
   return 1;
  if (pclient->buf[0] == '#' && pclient->buf[1] != '#') //#表示用戶要指定另一個用戶進行聊天
  {
   SOCKET socket = FindClient(&pclient->buf[1]); //驗證一下客戶是否存在
   if (socket != INVALID_SOCKET)
   {
    pClient c = (pClient)malloc(sizeof(_Client));
    c = FindClient(socket);      //只要改變ChatName,發(fā)送消息的時候就會自動發(fā)給指定的用戶了
    memset(pclient->ChatName, 0, sizeof(pclient->ChatName)); 
    memcpy(pclient->ChatName , c->userName,sizeof(pclient->ChatName));
   }
   else 
    send(pclient->sClient, "The user have not online or not exits.",64,0);
   continue;
  }

  pSend psend = (pSend)malloc(sizeof(_Send));
  //把發(fā)送人的用戶名和接收消息的用戶和消息賦值給結構體,然后當作參數(shù)傳進發(fā)送消息進程中
  memcpy(psend->FromName, pclient->userName, sizeof(psend->FromName));
  memcpy(psend->ToName, pclient->ChatName, sizeof(psend->ToName));
  memcpy(psend->data, pclient->buf, sizeof(psend->data));
  _beginthreadex(NULL, 0, ThreadSend, psend, 0, NULL);
  Sleep(200);
 }

 return 0;
}

//開啟接收消息線程
void StartRecv()
{
 pClient pclient = GetHeadNode();
 while (pclient = pclient->next)
  _beginthreadex(NULL, 0, ThreadRecv, pclient, 0, NULL);
}

//管理連接
unsigned __stdcall ThreadManager(void* param)
{
 while (1)
 {
  CheckConnection(); //檢查連接狀況
  Sleep(2000);  //2s檢查一次
 }

 return 0;
}

//接受請求
unsigned __stdcall ThreadAccept(void* param)
{
 _beginthreadex(NULL, 0, ThreadManager, NULL, 0, NULL);
 Init(); //初始化一定不要再while里面做,否則head會一直為NULL?。?!
 while (1)
 {
  //創(chuàng)建一個新的客戶端對象
  pClient pclient = (pClient)malloc(sizeof(_Client));

  //如果有客戶端申請連接就接受連接
  if ((pclient->sClient = accept(g_ServerSocket, (SOCKADDR*)&g_ClientAddr, &g_iClientAddrLen)) == INVALID_SOCKET)
  {
   printf("accept failed with error code: %d\n", WSAGetLastError());
   closesocket(g_ServerSocket);
   WSACleanup();
   return -1;
  }
  recv(pclient->sClient, pclient->userName, sizeof(pclient->userName), 0); //接收用戶名和指定聊天對象的用戶名
  recv(pclient->sClient, pclient->ChatName, sizeof(pclient->ChatName), 0);

  memcpy(pclient->IP, inet_ntoa(g_ClientAddr.sin_addr), sizeof(pclient->IP)); //記錄客戶端IP
  pclient->flag = pclient->sClient; //不同的socke有不同UINT_PTR類型的數(shù)字來標識
  pclient->Port = htons(g_ClientAddr.sin_port);
  AddClient(pclient); //把新的客戶端加入鏈表中

  printf("Successfuuly got a connection from IP:%s ,Port: %d,UerName: %s , ChatName: %s\n",
   pclient->IP, pclient->Port, pclient->userName,pclient->ChatName);

  if (CountCon() >= 2)      //當至少兩個用戶都連接上服務器后才進行消息轉發(fā) 
   StartRecv();

  Sleep(2000);
 }
 return 0;
}

//啟動服務器
int StartServer()
{
 //存放套接字信息的結構
 WSADATA wsaData = { 0 };
 SOCKADDR_IN ServerAddr = { 0 };    //服務端地址
 USHORT uPort = 18000;      //服務器監(jiān)聽端口

 //初始化套接字
 if (WSAStartup(MAKEWORD(2, 2), &wsaData))
 {
  printf("WSAStartup failed with error code: %d\n", WSAGetLastError());
  return -1;
 }
 //判斷版本
 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
 {
  printf("wVersion was not 2.2\n");
  return -1;
 }
 //創(chuàng)建套接字
 g_ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if (g_ServerSocket == INVALID_SOCKET)
 {
  printf("socket failed with error code: %d\n", WSAGetLastError());
  return -1;
 }

 //設置服務器地址
 ServerAddr.sin_family = AF_INET;//連接方式
 ServerAddr.sin_port = htons(uPort);//服務器監(jiān)聽端口
 ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//任何客戶端都能連接這個服務器

 //綁定服務器
 if (SOCKET_ERROR == bind(g_ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)))
 {
  printf("bind failed with error code: %d\n", WSAGetLastError());
  closesocket(g_ServerSocket);
  return -1;
 }
 //設置監(jiān)聽客戶端連接數(shù)
 if (SOCKET_ERROR == listen(g_ServerSocket, 20000))
 {
  printf("listen failed with error code: %d\n", WSAGetLastError());
  closesocket(g_ServerSocket);
  WSACleanup();
  return -1;
 }

 _beginthreadex(NULL, 0, ThreadAccept, NULL, 0, 0);
 for (int k = 0;k < 100;k++) //讓主線程休眠,不讓它關閉TCP連接.
  Sleep(10000000);

 //關閉套接字
 ClearClient();
 closesocket(g_ServerSocket);
 WSACleanup();
 return 0;
}

int main()
{
 StartServer(); //啟動服務器

 return 0;
}

Client code:

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#pragma comment(lib,"ws2_32.lib")
#define RECV_OVER 1
#define RECV_YET 0
char userName[16] = { 0 };
char chatName[16] = { 0 };
int iStatus = RECV_YET;
//接受數(shù)據
unsigned __stdcall ThreadRecv(void* param)
{
 char buf[128] = { 0 };
 while (1)
 {
  int ret = recv(*(SOCKET*)param, buf, sizeof(buf), 0);
  if (ret == SOCKET_ERROR)
  {
   Sleep(500);
   continue;
  }
  if (strlen(buf) != 0)
  {
   printf("%s\n", buf);
   iStatus = RECV_OVER;
  }
  else
   Sleep(100); 


 }
 return 0;
}

//發(fā)送數(shù)據
unsigned __stdcall ThreadSend(void* param)
{
 char buf[128] = { 0 };
 int ret = 0;
 while (1)
 {
  int c = getch();
  if (c == 27) //ESC ASCII是27
  {
   memset(buf, 0, sizeof(buf));
   printf("Please input the chat name:");
   gets_s(buf);
   char b[17] = { 0 };
   sprintf(b, "#%s", buf);
   ret = send(*(SOCKET*)param,b , sizeof(b), 0);
   if (ret == SOCKET_ERROR)
    return 1;
   continue;
  }
  if(c == 72 || c == 0 || c == 68)//為了顯示美觀,加一個無回顯的讀取字符函數(shù)
   continue;     //getch返回值我是經過實驗得出如果是返回這幾個值,則getch就會自動跳過,具體我也不懂。
  printf("%s: ", userName);
  gets_s(buf);
  ret = send(*(SOCKET*)param, buf, sizeof(buf), 0);
  if (ret == SOCKET_ERROR)
   return 1;
 }
 return 0;
}



//連接服務器
int ConnectServer()
{
 WSADATA wsaData = { 0 };//存放套接字信息
 SOCKET ClientSocket = INVALID_SOCKET;//客戶端套接字
 SOCKADDR_IN ServerAddr = { 0 };//服務端地址
 USHORT uPort = 18000;//服務端端口
 //初始化套接字
 if (WSAStartup(MAKEWORD(2, 2), &wsaData))
 {
  printf("WSAStartup failed with error code: %d\n", WSAGetLastError());
  return -1;
 }
 //判斷套接字版本
 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
 {
  printf("wVersion was not 2.2\n");
  return -1;
 }
 //創(chuàng)建套接字
 ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 if (ClientSocket == INVALID_SOCKET)
 {
  printf("socket failed with error code: %d\n", WSAGetLastError());
  return -1;
 }
 //輸入服務器IP
 printf("Please input server IP:");
 char IP[32] = { 0 };
 gets_s(IP);
 //設置服務器地址
 ServerAddr.sin_family = AF_INET;
 ServerAddr.sin_port = htons(uPort);//服務器端口
 ServerAddr.sin_addr.S_un.S_addr = inet_addr(IP);//服務器地址

 printf("connecting......\n");
 //連接服務器
 if (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)))
 {
  printf("connect failed with error code: %d\n", WSAGetLastError());
  closesocket(ClientSocket);
  WSACleanup();
  return -1;
 }
 printf("Connecting server successfully IP:%s Port:%d\n",
  IP, htons(ServerAddr.sin_port));
 printf("Please input your UserName: ");
 gets_s(userName);
 send(ClientSocket, userName, sizeof(userName), 0);
 printf("Please input the ChatName: ");
 gets_s(chatName);
 send(ClientSocket, chatName, sizeof(chatName), 0);
 printf("\n\n");

 _beginthreadex(NULL, 0, ThreadRecv, &ClientSocket, 0, NULL); //啟動接收和發(fā)送消息線程
 _beginthreadex(NULL, 0, ThreadSend, &ClientSocket, 0, NULL);
 for (int k = 0;k < 1000;k++)
  Sleep(10000000);
 closesocket(ClientSocket);
 WSACleanup();
 return 0;
}

int main()
{
 ConnectServer(); //連接服務器
 return 0;
}

最后,需要改進的有以下幾點:

1.沒有消息記錄,所以最好用文件或者數(shù)據庫的方式記錄,個人推薦數(shù)據庫。

2.沒有用戶注冊,登陸的操作,也是用文件或者數(shù)據庫來弄。程序一運行就讀取數(shù)據庫信息就行。

3.群聊功能沒有弄,這個其實很簡單,就是服務器不管3721,把接收到的消息轉發(fā)給所有在線用戶。

4.沒有離線消息,這個就用數(shù)據庫存儲離線消息,然后用戶上線后立即發(fā)送過去就行。

最后總結一下,沒有數(shù)據庫的聊天程序果然功能簡陋~,C語言寫的程序要注意對內存的操作。還有TCP方式的連接太費時費內存(用戶量達的時候)。

C語言版聊天程序(TCP版本,接下來還有UDP版本)到這里結束,歡迎各位提出自己的看法。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • C++實現(xiàn)LeetCode(20.驗證括號)

    C++實現(xiàn)LeetCode(20.驗證括號)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(20.驗證括號),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2021-07-07
  • Cocos2d-x觸摸事件實例

    Cocos2d-x觸摸事件實例

    這篇文章主要介紹了Cocos2d-x觸摸事件實例,本文代碼中包含大量注釋來說明Cocos2d-x中的觸摸事件使用示例,需要的朋友可以參考下
    2014-09-09
  • C語言實現(xiàn)快速排序

    C語言實現(xiàn)快速排序

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)快速排序算法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • C++超詳細講解智能指針

    C++超詳細講解智能指針

    為了解決內存泄漏的問題,C++中提出了智能指針。內存泄漏的產生原因有很多,即使我們正確的使用malloc和free關鍵字也有可能產生內存泄漏,如在malloc和free之間如果存在拋異常,那也會產生內存泄漏。這種問題被稱為異常安全
    2022-06-06
  • C++逆向分析移除鏈表元素實現(xiàn)方法詳解

    C++逆向分析移除鏈表元素實現(xiàn)方法詳解

    這篇文章主要介紹了C++實現(xiàn)LeetCode(203.移除鏈表元素),本篇文章通過逆向分析的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下
    2022-11-11
  • 用c 獲取文件MD5值的實現(xiàn)方法

    用c 獲取文件MD5值的實現(xiàn)方法

    本篇文章是對用c語言獲取文件MD5值的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C語言中的文件操作詳解

    C語言中的文件操作詳解

    這篇文章主要介紹了C語言中的文件操作詳解,使用文件可以將數(shù)據直接存放到電腦的硬盤上,做到了數(shù)據的持久化
    2022-07-07
  • 淺析C#與C++相關概念的比較

    淺析C#與C++相關概念的比較

    以下是對C#與C++的相關概念進行了比較和介紹。需要的朋友可以過來參考下
    2013-08-08
  • C++類與對象及構造函數(shù)析構函數(shù)基礎詳解

    C++類與對象及構造函數(shù)析構函數(shù)基礎詳解

    這篇文章主要為大家介紹了C++類與對象及構造函數(shù)析構函數(shù)基礎詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • 簡單掌握Linux系統(tǒng)中fork()函數(shù)創(chuàng)建子進程的用法

    簡單掌握Linux系統(tǒng)中fork()函數(shù)創(chuàng)建子進程的用法

    fork()函數(shù)只能在類Unix系統(tǒng)下使用,因為需要引入unistd頭文件,這里我們就來簡單掌握Linux系統(tǒng)中fork()函數(shù)創(chuàng)建子進程的用法,需要的朋友可以參考下
    2016-06-06

最新評論