设为首页 加入收藏

TOP

C++ Socket 学习笔记(四)
2016-09-12 19:03:14 】 浏览:1132
Tags:Socket 学习 笔记

fork 和 exec 函数

    /* 函数功能:创建子进程; 
     * 返回值: 
     * (1)在子进程中,返回0; 
     * (2)在父进程中,返回新创建子进程的进程ID; 
     * (3)若出错,则范回-1; 
     * 函数原型: 
     */  
    #include 
  
     
    pid_t fork(void);  
    /* 说明: 
     * 该函数调用一次若成功则返回两个值: 
     * 在调用进程(即父进程)中,返回新创建进程(即子进程)的进程ID; 
     * 在子进程返回值是0; 
     * 因此,可以根据返回值判断进程是子进程还是父进程; 
     */  

    /* exec 序列函数 */  

    /* 
     * 函数功能:把当前进程替换为一个新的进程,新进程与原进程ID相同; 
     * 返回值:若出错则返回-1,若成功则不返回; 
     * 函数原型: 
     */  
    #include 
   
     int execl(const char *pathname, const char *arg, ...); int execv(const char *pathnam, char *const argv[]); int execle(const char *pathname, const char *arg, ... , char *const envp[]); int execve(const char *pathnam, char *const argv[], char *const envp[]); int execlp(const char *filename, const char *arg, ...); int execvp(const char *filename, char *const argv[]); /* 6 个函数的区别如下: * (1)待执行的程序文件是 文件名 还是由 路径名 指定; * (2)新程序的参数是 一一列出 还是由一个 指针数组 来引用; * (3)把调用进程的环境传递给新程序 还是 给新程序指定新的环境; */ 
   
  

exec 6个函数在函数名和使用语法的规则上都有细微的区别,下面就从可执行文件查找方式、参数传递方式及环境变量这几个方面进行比较。

查找方式:前4个函数的查找方式都是完整的文件目录路径 pathname ,而最后两个函数(也就是以p结尾的两个函数)可以只给出文件名 filename,系统就会自动按照环境变量 “$PATH” 所指定的路径进行查找。 参数传递方式:exec 序列函数的参数传递有两种方式:一种是逐个列举的方式,而另一种则是将所有参数整体构造指针数组传递。在这里是以函数名的第5位字母来区分的,字母为 “l”(list)的表示逐个列举参数的方式,其语法为 const char *arg;字母为 “v”(vertor)的表示将所有参数整体构造指针数组传递,其语法为 char *const argv[]。读者可以观察 execl()、execle()、execlp() 的语法与 execv()、execve()、execvp() 的区别。这里的参数实际上就是用户在使用这个可执行文件时所需的全部命令选项字符串(包括该可执行程序命令本身)。要注意的是,这些参数必须以NULL结束。 环境变量:exec 序列函数可以默认系统的环境变量,也可以传入指定的环境变量。这里以 “e”(environment)结尾的两个函数 execle() 和 execve() 就可以在 envp[] 中指定当前进程所使用的环境变量。

并发服务器

当要求一个服务器同时为多个客户服务时,需要并发服务器。TCP 并发服务器,它们为每个待处理的客户端连接调用 fork 函数派生一个子进程。当一个连接建立时,accept 返回,服务器接着调用 fork 函数,然后由子进程服务客户端,父进程则等待另一个连接,此时,父进程必须关闭已连接套接字。

close 和 shutdown 函数

当要关闭套接字时,可使用 close 和 shutdown 函数,其描述如下:

 /* 函数功能:关闭套接字,若是在 TCP 协议中,并终止 TCP 连接; 
     * 返回值:若成功则返回0,若出错则返回-1; 
     * 函数原型: 
     */  
    #include 
  
     
    int close(int sockfd);  

    /* 
     * 函数功能:关闭套接字上的输入或输出; 
     * 返回值:若成功则返回0,若出错返回-1; 
     * 函数原型: 
     */  
    #include 
   
     int shutdown(int sockfd, int how); /* * 说明: * sockfd表示待操作的套接字描述符; * how表示具体操作,取值如下: * (1)SHUT_RD 关闭读端,即不能接收数据 * (2)SHUT_WR 关闭写端,即不能发送数据 * (3)SHUT_RDWR 关闭读、写端,即不能发送和接收数据 * */ 
   
  

getsockname 和 getpeername 函数

为了获取已绑定到套接字的地址,我们可以调用函数 getsockname 来实现:

    /* 
     * 函数功能:获取已绑定到一个套接字的地址; 
     * 返回值:若成功则返回0,若出错则返回-1; 
     * 函数原型: 
     */  
    #include 
  
     

    int getsockname(int sockfd, struct sockaddr *addr, socklen_t *alenp);  
    /* 
     * 说明: 
     * 调用该函数之前,设置alenp为一个指向整数的指针,该整数指定缓冲区sockaddr的大小; 
     * 返回时,该整数会被设置成返回地址的大小,如果该地址和提供的缓冲区长度不匹配,则将其截断而不报错; 
     */  
    /* 
     * 函数功能:获取套接字对方连接的地址; 
     * 返回值:若成功则返回0,若出错则返回-1; 
     * 函数原型: 
     */  
    #include 
   
     int getpeername(int sockfd, struct sockaddr *addr, socklen_t *alenp); /* * 说明: * 该函数除了返回对方的地址之外,其他功能和getsockname一样; */ 
   
  

出处


测试实例

客户端

#include 
  
   
#include 
   
     #include 
    
      using namespace std; #pragma comment(lib, "ws2_32.lib") #define xPort 8000 #define xIP "127.0.0.1" int main() { const int xBUF_SIZE = 64; WSADATA wsd; //WSADATA变量 SOCKET xServer; //服务器套接字 SOCKET xClient; //客户端套接字 SOCKADDR_IN xaddrServ; //服务器地址 char recBuf[xBUF_SIZE]; //接受数据缓冲区 char sendBuf[xBUF_SIZE]; //返回数据缓冲区 int retVal; //返回值 //初始化套结字动态库,请求2.2版本winsock if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { cout << "WSAStartup failed!" << endl; return 1; } /* //创建socket操作 // SOCKET socket(int af, int type, int protocol); // 第一个参数,指定地址簇(TCP/IP只能是AF_INET,也可写成PF_INET) // 第二个,选择套接字的类型(流式套接字),第三个,特定地址家族相关协议(0为自动) */ //创建套接字 xClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(INVALID_SOCKET == xClient) { cout << "socket failed!" << endl; WSACleanup();//释放套接字资源; return -1; } //服务器套接字地址 xaddrServ.sin_family = AF_INET; xaddrServ.sin_port = htons(xPort); xaddrServ.sin_addr.s_addr = inet_addr(xIP); /* // 将套接字xClient与远程主机相连 // int connect( SOCKET s, const struct sockaddr* name, int namelen); // 第一个参数:需要进行连接操作的套接字 // 第二个参数:设定所需要连接的地址信息 // 第三个参数:地址的长度 */ //连接服务器 retVal = connect(xClient, (LPSOCKADDR)&xaddrServ, sizeof(xaddrServ)); if(SOCKET_ERROR == retVal) { cout << "connect failed!" << endl; closesocket(xClient); //关闭套接字 WSACleanup(); //释放套接字资源 return -1; } ///三次握手完成 // 客户端与用户端进行通信 /* // send(), 在套接字上发送数据 // int send( SOCKET s, const char* buf, int len, int flags); // 第一个参数,需要发送信息的套接字, // 第二个参数,包含了需要被传送的数据, // 第三个参数是buffer的数据长度, // 第四个参数,一些传送参数的设置 // recv(), 在套接字上接收数据 // int recv( SOCKET s, char* buf, int len, int flags); // 第一个参数,建立连接后的套接字, // 第二个参数,接收数据 // 第三个参数,接收数据的长度, // 第四个参数,一些传送参数的设置 */ cout << "*************************客户端**********************"<< endl; while(true) { memset(sendBuf, '/0', xBUF_SIZE); cout << "向服务器发送数据:"; cin >> sendBuf; retVal = send(xClient, sendBuf, xBUF_SIZE, 0); if (SOCKET_ERROR == retVal) { cout << "send failed!" << endl; closesocket(xClient); //关闭套接字 WSACleanup(); //释放套接字资源; return -1; } if(sendBuf[0] == '0') break; memset(recBuf, '/0', sizeof(recBuf)); recv(xClient, recBuf, xBUF_SIZE , 0); // 接收服务器端的数据, 只接收5个字符 cout <<"从服务器接收数据:"<< recBuf << endl; cout<
     
      

服务器

#include 
       
        
#include 
        
          #include 
         
           #include 
          
            using namespace std; #pragma comment(lib, "ws2_32.lib") #define xPort 8000 #define xIP "127.0.0.1" int m
首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++学习笔记(五):高级编程:文.. 下一篇C++学习笔记(二):指针,引用,..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目