⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uclinux-server.txt

📁 uclinux的服务器程序,非常经典,可以作为嵌入式项目的参考资料
💻 TXT
字号:
uClinux本身就是一个网络的产物,它可以从网上供人们自由免费的下载,正是通过很多爱好者利用网络修改,改善Linux,才得到我们现在的uClinux,所以没有网络可以说就看不到今天的uClinux。因此,在学习uClinux的时候,就不能不涉及到网络,而要掌握在uClinux下设计用户应用程序,就必须要学习有关uClinux下的网络编程。本节主要讲述当前在网络编程中被广泛使用的socket。
socket一般被翻译为“套接字”,简而言之就是网络进程中的ID。
其实网络通信,本质就是进程间的通信,在网络中,每个节点都有唯一一个网络地址,即通常说的IP地址,两个进程在通信的时候,必须首先要确定通信双方的网络地址。但是网络地址只能确定进程所在的PC机,然而同一台PC可能有好几个网络进程,只有网络地址是不能够确定到底是哪个进程,所以套接字还需要提供其他信息,那就是端口号,同一台PC机,一个端口号只能分配给一个进程。所以,网络地址和端口号结合在一起,才可以共同确定整个Internet中的一个网络进程。
套接字最常用的有两种:流式套接字(Stream Socket)和数据报套接字(Datagram Socket)。在Linux中,分别称为”SOCK_STREAM”和”SOCK_DGRAM”。
这两种套接字的区别在于它们使用不同的协议。流式套接字使用TCP协议,数据报套接字使用的是UDP协议。
TCP(Transmission Control Protocol)传输控制协议,是TCP/IP体系中的运输层协议,是面向连接的,因而可提供可靠的,按序传送数据流,它的可靠是因为它使用三段握手协议来传输数据,并且采用“重发机制”确保数据的正确发送,接收端收到数据后要发出一个肯定确认,而发送端必须接收到接收端的确认信息后,否则发送端会重发数据。同时TCP是无错误传递的,有自己的检错和纠错机制,使用TCP协议的套接字是属于流式套接字。大家熟知的telnet就是使用的流式套接字。
UDP(User Datagram Protocol)用户数据报协议提供无连接的不可靠的服务,在传送数据之前不需要建立连接。远地主机在接收接收到UDP数据报后,不需要给出任何应答,这样的话,如果发送一个数据报,可能到达也可能丢失。如果发送多个包,到达接收端的次序可能是颠倒的。数据报套接字有时候也称为“无连接套接字”,大家熟悉的TFTP和NFS使用的就是该协议。
大多数情况下,如果只是将数据包发送给给定地址的机器,是不能够确定到底把数据包发送给机器哪一个进程的,端口号的指定才能够更明确的指明。适用于通信的用户应用程序可以使用从1到65535的任何一个端口号,并将它分配给端口。这些号通常分成以下几个范围段:
端口0,不使用。如果传递的端口号是0,就会为进程分配一个1024到5000之间的一个没有使用的端口。
端口1~255,保留给特定的服务,如FTP,远程网,FINGER等。
端口256~1023,保留给别的一般服务如Routing function(路由函数)。
端口1024~4999,可以被任意的客户机端口所使用,客户机套接字通常会使用这个范围段的端口。
端口5000~65535,为用户定义的服务器端口所使用。如果一个客户机需要事先知道服务器的端口,那么服务器套接字就应该使用这个范围的端口值。
下面结合一个具体的服务器端的例子,使读者熟悉socket编程的方法。
/*******************************************************
 * Institute of Automation, Chinese Academy of Sciences 
 * File Name: 	comsamp.c
 * Description:communication with socket 	
 * Author:		Xueyuan Nie
 * Date:		
 *******************************************************/

#include <float.h>
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>    
#include <unistd.h>   
#include <netinet/in.h> 
#include <netdb.h>
#include <sys/time.h>  
#include <sys/types.h>
#include <sys/socket.h>

/*=========*
 * Defines *
 *=========*/
#ifndef TRUE
#define FALSE 0
#define TRUE  1
#endif

#ifndef EXIT_FAILURE
#define EXIT_FAILURE  1
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS  0
#endif

#ifndef EXT_NO_ERROR
#define EXT_NO_ERROR 0
#endif
#ifndef EXT_ERROR
#define EXT_ERROR    1
#endif

#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif

#ifndef SOCK_ERR
#define SOCK_ERR -1
#endif
/*==================================*
 * Global data local to this module *
 *==================================*/
typedef int SOCKET;
typedef struct ConnectData_tag {
    int     port;
	int     waitForStart;
    SOCKET    sFd;   /* socket to listen/accept on         */
    SOCKET    msgFd; /* socket to send/receive messages    */ 
} ConnectData;

ConnectData *CD;
int          i=0;
int          connectionMade = 0; 

/*=================*
 * Local functions *
 *=================*/
void prompt_info(int signumber)   
{
	char src[]="this is a test for socket\n";
	int nBytesToSet=strlen(src);
   send(CD->msgFd, src, nBytesToSet, 0);
}

void init_sigaction(void)
{
   struct sigaction act;
   act.sa_handler=prompt_info;
   act.sa_flags=0;
   sigemptyset(&act.sa_mask);  
   sigaction(SIGPROF,&act,NULL);
}

void init_time(double t_usec)
{
    struct itimerval value;
	  int int_usec;
	  int_usec=(int)(t_usec*1000000);
    value.it_value.tv_sec=0;       
    value.it_value.tv_usec=int_usec;       value.it_interval=value.it_value;
    setitimer(ITIMER_PROF,&value,NULL);
}

int ModeInit(void)
{
    int error = EXT_NO_ERROR;
    
    error = ExtInit(CD);
    if (error != EXT_NO_ERROR) goto EXIT_POINT;
    printf("Succeeded in creating listening Socket by NXY\n");
EXIT_POINT:
    return(error);
} /* end ModeInit */

/* Function: ExtInit 
 * Abstract:
 *  Called once at program startup to do any initialization.
 *  A socket is created to listen for
 *  connection requests from the client.  EXT_NO_ERROR is returned 
*   on success, EXT_ERROR on failure.
*  NOTES:
 *   This function should not block.
 */
int ExtInit(ConnectData *UD)
{
    int                sockStatus;     
    struct sockaddr_in serverAddr;
    int              sFdAddSize = sizeof(struct sockaddr_in);
    int              option     = 1;     
    int              port       = 17725;
    int              error      = EXT_NO_ERROR;
    SOCKET           sFd        = INVALID_SOCKET;
        
#ifdef WIN32
    WSADATA data;
  
    if (WSAStartup((MAKEWORD(1,1)),&data)) {
        fprintf(stderr,"WSAStartup() call failed.\n");
        error = EXT_ERROR;
        goto EXIT_POINT;
    }
#endif
  
    /*
     * Create a TCP-based socket.
     */
    memset((char *) &serverAddr,0,sFdAddSize);
    serverAddr.sin_family      = AF_INET;
    serverAddr.sin_port        = htons(port);
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  
    sFd = socket(AF_INET, SOCK_STREAM, 0);
    if (sFd == INVALID_SOCKET) {
        fprintf(stderr,"socket() call failed.\n");
        error = EXT_ERROR;
        goto EXIT_POINT;
    }

    /*
     * Listening socket should always use the SO_REUSEADDR option
     * ("Unix Network Programming - Networking APIs:Sockets and XTI",
     *   Volume 1, 2nd edition, by W. Richard Stevens).
     */
    sockStatus =         setsockopt(sFd,SOL_SOCKET,SO_REUSEADDR,(char*)&option,sizeof(option));
    if (sockStatus == SOCK_ERR) {
        fprintf(stderr,"setsocketopt() call failed.\n");
        error = EXT_ERROR;
        goto EXIT_POINT;
    }

    sockStatus = 
        bind(sFd, (struct sockaddr *) &serverAddr, sFdAddSize);
    if (sockStatus == SOCK_ERR) {
        fprintf(stderr,"bind() call failed.\n");
        error = EXT_ERROR;
        goto EXIT_POINT;
    }
  
    sockStatus = listen(sFd, 1); 
    if (sockStatus == SOCK_ERR) {
        fprintf(stderr,"listen() call failed.\n");
        error = EXT_ERROR;
        goto EXIT_POINT;
    }

EXIT_POINT:
    UD->msgFd = INVALID_SOCKET;
    UD->port=17725;
    if (error == EXT_ERROR) {
        if (sFd != INVALID_SOCKET) {
            close(sFd);
        }
        UD->sFd = INVALID_SOCKET;
    } else {
        UD->sFd = sFd;
    }
    return(error);
} /* end ExtInit */


int OpenConnection(ConnectData *UD)  
{
    struct sockaddr_in clientAddr;
    int              sFdAddSize     = sizeof(struct sockaddr_in);
    
    int                error          = EXT_NO_ERROR;
    SOCKET             msgFd          = INVALID_SOCKET;
    const SOCKET       sFd            = UD->sFd;
    /*
     * Wait to accept a connection on the message socket.
     */
    msgFd = accept(sFd, (struct sockaddr *)&clientAddr,
                   &sFdAddSize);
    if (msgFd == INVALID_SOCKET) {
        fprintf(stderr,"accept() for message socket failed.\n");
        error = EXT_ERROR;
        goto EXIT_POINT;
    } 
    connectionMade = 1;

EXIT_POINT:
    if (error != EXT_NO_ERROR) {
        if (msgFd != INVALID_SOCKET) {
            close(msgFd);
        }
       
        UD->msgFd = INVALID_SOCKET;
    } else {
        UD->msgFd = msgFd;
		if(msgFd !=INVALID_SOCKET)
			printf("Succeeded in creating  socket!\n"); 
    }
  
    return(error);
} 


/* Function: main 
 *
 * Abstract:
 *      
 */
int main(int argc, const char *argv[])
{
    int error;
	const char *option=argv[1];
	
	CD=(ConnectData *)malloc(sizeof(ConnectData));
    memset(CD,0,sizeof(ConnectData));
	if (strcmp(option, "-w") == 0)
		CD->waitForStart=1;
	else
        CD->waitForStart=0;
	ModeInit();

    while((CD->waitForStart)&&(connectionMade==0))
	{
    	error=OpenConnection(CD);
		if(error) exit(EXIT_FAILURE);
	}
     
	init_sigaction();
    init_time(2.0);
    while (1);

    return(EXIT_SUCCESS);

} /* end main */
下面就结合本例,介绍如何在linux(uClinux)下建立通信双方中服务器端的程序。
本例是一个服务器程序,采用流式套接字,因为流式套接字提供了一种可靠的面向连接的数据传输方法。正如它的名字所指的那样,不管是对单个的数据报,还是对于数据包,流式套接字都提供一种流式数据传输。流式套接字由socket()函数调用来创建,而且调用时必须用bind()函数为它分配一个地址。
在创建好一个套接字,并赋给它一个地址之后,需要用一种方法来建立和客户机的连接,为了做到这一点,要使用listen()函数。该函数告诉套接字开始侦听客户机的连接请求。一旦将套接字设置成侦听连接后,实际的连接就可以由accept()函数来完成。如果连接成功的接受,accept()函数将返回一个新套接字的描述符,正是由accept()函数所创建的这个新套接字会被用作以后处理新的连接。在该例程中,ConnectData结构体中的msgFd套接字就是用来真正和客户端进行通信的socket。
原来的侦听套接字将会继续侦听新的连接请求,而新的请求可能会通过accept()函数的再一次调用而获得接受。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -