网络编程基础--套接字基础编程

来源:互联网 发布:上海医工院怎么样知乎 编辑:程序博客网 时间:2024/05/03 17:01

1.建立和销毁套接字

#include<sys/types.h>
#include<sys/socket.h>
定义函数 int socket(int domain,int type,int protocol);
函数说明 socket()用来建立一个新的socket,也就是向系统注册,通知系统建立一通信端口。参数domain 指定使用何种的地址类型,完整的定义在/usr/include/bits/socket.h 内,底下是常见的协议:
PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX 进程通信协议
PF_INET/AF_INET Ipv4网络协议
PF_INET6/AF_INET6 Ipv6 网络协议
PF_IPX/AF_IPX IPX-Novell协议
PF_NETLINK/AF_NETLINK 核心用户接口装置
PF_X25/AF_X25 ITU-T X.25/ISO-8208 协议
PF_AX25/AF_AX25 业余无线AX.25协议
PF_ATMPVC/AF_ATMPVC 存取原始ATM PVCs
PF_APPLETALK/AF_APPLETALK appletalk(DDP)协议
PF_PACKET/AF_PACKET 初级封包接口


参数 type有下列几种数值:
SOCK_STREAM 提供双向连续且可信赖的数据流,即TCP。支持OOB 机制,在所有数据传送前必须使用connect()来建立连线状态。
SOCK_DGRAM 使用不连续不可信赖的数据包连接
SOCK_SEQPACKET 提供连续可信赖的数据包连接
SOCK_RAW 提供原始网络协议存取
SOCK_RDM 提供可信赖的数据包连接
SOCK_PACKET 提供和网络驱动程序直接通信。
protocol用来指定socket所使用的传输协议编号,通常此参考不用管它,设为0即可。
返回值 成功则返回socket处理代码,失败返回-1。
错误代码 EPROTONOSUPPORT 参数domain指定的类型不支持参数type或protocol指定的协议
ENFILE 核心内存不足,无法建立新的socket结构
EMFILE 进程文件表溢出,无法再建立新的socket
EACCESS 权限不足,无法建立type或protocol指定的协议
ENOBUFS/ENOMEM 内存不足
EINVAL 参数domain/type/protocol不合法


如果不需要使用时,使用close函数即可关闭一个套接字,想关闭文件一样。


……

int fd;

fd=socket(AF_INET,type,0);

……

close(fd);

……


2.地址绑定


#include<sys/types.h>
#include<sys/socket.h>
定义函数 int bind(int sockfd,struct sockaddr * my_addr,int addrlen);
函数说明 bind()用来设置给参数sockfd的socket一个名称。此名称由参数my_addr指向一sockaddr结构,对于不同的socket domain定义了一个通用的数据结构
struct sockaddr
{
unsigned short int sa_family;
char sa_data[14];
};
sa_family 为调用socket()时的domain参数,即AF_xxxx值。
sa_data 最多使用14个字符长度。
此sockaddr结构会因使用不同的socket domain而有不同结构定义,
例如使用AF_INET domain,其socketaddr结构定义便为
struct socketaddr_in
{
unsigned short int sin_family;
uint16_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr
{
uint32_t s_addr;
};
sin_family 即为sa_family
sin_port 为使用的port编号
sin_addr.s_addr 为IP 地址
sin_zero 未使用。
参数 addrlen为sockaddr的结构长度。
返回值 成功则返回0,失败返回-1,错误原因存于errno中。
错误代码 EBADF 参数sockfd 非合法socket处理代码。
EACCESS 权限不足
ENOTSOCK 参数sockfd为一文件描述词,非socket。


例:命名套接字描述符s的协议为AF_INET,地址为127.0.0.1,端口号为10000.


struct sockaddr_in sockaddr1;//申请地址结构空间

memset(&sockaddr1,0,sizeof(sockaddr1));//清空空间

sockaddr1.sin_family=AF_INET;//协议族

sockaddr1.sin_addr.s_addr=inet_addr("127.0.0.1");//ip地址

sockaddr1.sin_port=htons(10000);//端口号

bin(s,(struct sockaddr *)&sockaddr1,sizeof(sockaddr1));


上面指定了IP地址,但是有的主机可能有多个IP地址或IP地址是动态分配的,则我们就应该有系统指定一个本机的ip地址。当结构sockaddr_in的IP地址成员sin_addr赋值为常数INADDR_ANY时,系统将自动指定套接字的ip地址。


例:命名套接字描述符s的协议为AF_INET,地址由系统指定,端口号为10000.


struct sockaddr_in sockaddr1;//申请地址结构空间

memset(&sockaddr1,0,sizeof(sockaddr1));//清空空间

sockaddr1.sin_family=AF_INET;//协议族

sockaddr1.sin_addr.s_addr=htonl(INADDR_ANY);//ip地址

sockaddr1.sin_port=htons(10000);//端口号

bin(s,(struct sockaddr *)&sockaddr1,sizeof(sockaddr1));



3.建立一个连接


有了套接字之后,就可以建立一个连接了。

#include<sys/types.h>
#include<sys/socket.h>
定义函数 int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
函数说明 connect()用来将参数sockfd 的socket 连至参数serv_addr 指定的网络地址。结构sockaddr请参考bind()。参数addrlen为sockaddr的结构长度。
返回值 成功则返回0,失败返回-1,错误原因存于errno中。
错误代码 EBADF 参数sockfd 非合法socket处理代码
EFAULT 参数serv_addr指针指向无法存取的内存空间
ENOTSOCK 参数sockfd为一文件描述词,非socket。
EISCONN 参数sockfd的socket已是连线状态
ECONNREFUSED 连线要求被server端拒绝。
ETIMEDOUT 企图连线的操作超过限定时间仍未有响应。
ENETUNREACH 无法传送数据包至指定的主机。
EAFNOSUPPORT sockaddr结构的sa_family不正确。
EALREADY socket为不可阻断且先前的连线操作还未完成。


范例:

//connet.c

#include <unistd.h>
#include <sys/socket.h>

#define SLEEP_SEC 60 //休眠时间
#define MAX_TIMES 10 //最大连接次数

int connect_poll(int sockfd,const struct sockaddr * addr,socklen_t len)
{
int count;
for(count=0;count<=MAX_TIMES;count++){
if(connect(socket,addr,len)==0)
  return 0;
sleep(SLEEP_SEC); //延时,等待下一次连接
}
return -1;
}



linux下,使用如下函数监听客户端的连接请求:


int listen(int s,int backlog);
函数说明 listen()用来等待参数s 的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达此上限则client端将收到
ECONNREFUSED的错误。Listen()并未开始接收连线,只是设置socket为listen模式,真正接收client端连线的是accept()。通常
listen()会在socket(),bind()之后调用,接着才调用accept()。
返回值 成功则返回0,失败返回-1,错误原因存于errno
附加说明 listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果socket为AF_INET则参数backlog 最大值可设至128。
错误代码 EBADF 参数sockfd非合法socket处理代码
EACCESS 权限不足
EOPNOTSUPP 指定的socket并未支援listen模式。



服务器端接受请求用如下的函数:


#include<sys/types.h>
#include<sys/socket.h>
定义函数 int accept(int s,struct sockaddr * addr,int * addrlen);
函数说明 accept()用来接受参数s的socket连线。参数s的socket必需先经bind()、listen()函数处理过,当有连线进来时 accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的socket能继续使用 accept()来接受新的连线要求。连线成功时,参数addr所指的结构会被系统填入远程主机(客户机)的地址数据,参数addrlen为scokaddr的结构长度。关于结构
sockaddr的定义请参考bind()。
返回值 成功则返回新的socket处理代码,失败返回-1,错误原因存于errno中。
错误代码 EBADF 参数s 非合法socket处理代码。
EFAULT 参数addr指针指向无法存取的内存空间。
ENOTSOCK 参数s为一文件描述词,非socket。
EOPNOTSUPP 指定的socket并非SOCK_STREAM。
EPERM 防火墙拒绝此连线。
ENOBUFS 系统的缓冲内存不足。
ENOMEM 核心内存不足。


4.最简单的网络应用程序--服务器端

接受客户的一个字符串,并将它转化为小写字母。


//server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

#define MAX_LINE 100

void my_fun(char * p)
{
    if(p == NULL)
        return;

    for (; *p != '/0'; p++)
        if(*p >= 'A' && *p <= 'Z')
            *p = *p -'A'+ 'a';
}

int main(void)
{
     struct sockaddr_in sin;
     struct sockaddr_in cin;
     int l_fd;
     int c_fd;
     socklen_t len;
     char buf[MAX_LINE];
     char addr_p[INET_ADDRSTRLEN];
     int port = 8000;
     int n;
     
     bzero(&sin, sizeof(sin));
     sin.sin_family = AF_INET; //ipv4
     sin.sin_addr.s_addr = INADDR_ANY; //服务器端可接受任何地址
     sin.sin_port = htons(port);//端口号转化为网络字节序
  
     l_fd = socket(AF_INET, SOCK_STREAM, 0); //使用tcp建立套接字
  
     bind(l_fd, (struct sockaddr *)&sin, sizeof(sin));//将套接字和地址绑定
  
     listen(l_fd, 10); //开始监听连接请求
  
     printf("waiting .../n");
  
    while(1){//服务器端一般都是死循环
                //接受连接请求,从此函数返回后,就可以真正开始通信了
        c_fd = accept(l_fd, (struct sockaddr *) &cin, &len);

        n = read(c_fd, buf, MAX_LINE); //读取客户端传来的数据

        inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p)); //将客户端地址转换为字符串
        printf("client IP is %s, port is %d/n", addr_p, ntohs(sin.sin_port));
            printf("content is : %s/n", buf);
       
        my_fun(buf);
      
        write(c_fd, buf, n); //将转换后的字符串发回客户端
        
        close(c_fd);
    }

    if(close(l_fd) == -1){
        perror("fail to close");
        exit(1);
    }

    return 0;
}


本例主机自己和自己通信。



5.最简单的网络应用程序--客户端


//client.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

#define MAX_LINE 100
  
int main(int argc, char *argv[])
{
     struct sockaddr_in sin;//服务器的地址
     char buf[MAX_LINE];
     int sfd;
        int port = 8000;//要和服务器端一样才行
     char *str = "test sting"; //默认的字符串
  
     if (argc > 1)
          str = argv[1];//从命令行参数中取得用户输入的串
  
     bzero(&sin, sizeof(sin));
     sin.sin_family = AF_INET;//ipv4
  
     inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
     sin.sin_port = htons(port);
  
     sfd = socket(AF_INET, SOCK_STREAM, 0); //创建套接字

     connect(sfd, (struct sockaddr_in *)&sin, sizeof(sin));

     write(sfd, str, strlen(str) + 1);
  
     read(sfd, buf, MAX_LINE);

     printf("recive from server: %s/n", buf);

     close(sfd);
   
    return 0;
}



6.使用文件读写函数读写套接字



相对于本地读写,网络读写时要注意:延迟可能很大;应用程序可能要处理因为中断或网络连接等问题造成的读写操作细长返回。

对于第一个问题,使用非阻塞I/O或者多路I/O转换。网络环境的读写操作经常会因为信号中断而异常返回,这是read和write函数返回 -1,errno错误号被设置为EINTR。遇到这种情况,应该从上次成功读写的地方重新进行读写,对于其他的出错异常,则应该根据错误号打印相应的错误原因。


可使用如下自己定义的函数来解决上述问题:


//iolib.h

extern ssize_t my_read(int fd, void *buffer, size_t length);
extern ssize_t my_write(int fd, void *buffer, size_t length);


//iolib.c

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>

ssize_t my_read(int fd, void *buf, size_t length)
{
    ssize_t done = length; //读入的字节数

    while(done > 0) { //如果因为信号中断而异常,则多次读取
        done = read(fd, buf, length);
      
        if(done != length)//出现异常
            if(errno == EINTR) //如果是信号中断导致的错误,则舍弃已读入的内容,重新读取
                done = length;
            else{
                perror("fail to read"); //其他错误则返回
                return -1;
            }
        else
            break;
    }

    return done; //返回实际读入的字节数
}

ssize_t my_write(int fd, void *buf, size_t length)
{
    ssize_t done = length;//实际写的字节数

    while(done > 0) { //如果因为信号中断而异常,则多次写
        done = write(fd, buf, length);

        if(done != length) //出现异常
            if(errno == EINTR) //如果是信号中断导致的错误,则舍弃已写入的内容,重新写入
                done = length;
            else{
                perror("fail to write"); //其他错误则返回
                return -1;
            }
        else
            break;
    }

    return done;//返回实际写入的字节数
}


7.使用完整读写函数的网络应用程序

作用同前面那个例子一样,只是使用了my_read和my_write代替了前面没有异常处理的版本。


//server.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "iolib.h"

#define MAX_LINE 100

void my_fun(char * p)
{
    if(p == NULL) /* 空串 */
        return;

    for (; *p != '/0'; p++)
        if(*p >= 'A'&& *p <= 'Z')
            *p = *p -'A'+ 'a';
}

int main(void)
{
     struct sockaddr_in sin;
     struct sockaddr_in cin;
     int l_fd;
     int c_fd;
     socklen_t len;
     char buf[MAX_LINE];
     char addr_p[INET_ADDRSTRLEN];
     int port = 8000;
    int n;
     
     bzero(&sin, sizeof(sin));

     sin.sin_family = AF_INET;
     sin.sin_addr.s_addr = INADDR_ANY;
     sin.sin_port = htons(port);
  
    if( (l_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("fail to creat socket");
        exit(1);
    }

    if(bind(l_fd, (struct sockaddr *) &sin, sizeof(sin)) == -1){
        perror("fail to bind");
        exit(1);
    }

    if(listen(l_fd, 10) == -1){
        perror("fail to listen");
        exit(1);
    }
   
    printf("waiting .../n");
  
    while(1){
        if( (c_fd = accept(l_fd, (struct sockaddr *) &cin, &len)) == -1){
            perror("fail to accept");
            exit(1);
        }

        n = my_read(c_fd, buf, MAX_LINE);
        if(n == -1)
            exit(1);
        else if(n == 0){
            printf("the connect has been closed/n");
            close(c_fd);
            continue;
        }
      
        inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p));
        printf("client IP is %s, port is %d/n", addr_p, ntohs(cin.sin_port));
            printf("content is : %s/n", buf);
       
        my_fun(buf);

        n = my_write(c_fd, buf, n);
        if(n == -1){
            exit(1);
        }
      
        if(close(c_fd) == -1){
            perror("fail to close");
            exit(1);
        }
    }

    if(close(l_fd) == -1){
        perror("fail to close");
        exit(1);
    }


    return 0;
}



//client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

#include "iolib.h"

#define MAX_LINE 100
  
int main(int argc, char *argv[])
{
     struct sockaddr_in sin;
     char buf[MAX_LINE];
     int s_fd;
    int port = 8000;
    char *str = "test sting";
    int n;
  
     if (argc > 1)
          str = argv[1];
  
     bzero(&sin, sizeof(sin));

     sin.sin_family = AF_INET;
     inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
     sin.sin_port = htons(port);
  
    if( (s_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        perror("fail to creat socket");
        exit(1);
    }

    if(connect(s_fd, (struct sockaddr_in *) &sin, sizeof(sin)) == -1){
        perror("fail to connect");
        exit(1);
    }

    n = my_write(s_fd, str, strlen(str) + 1);
    if(n == -1)
        exit(1);
  
    n = my_read(s_fd, buf, MAX_LINE);
    if(n == -1)
        exit(1);  
   
    printf("recive from server: %s/n", buf);

    if(close(s_fd) == -1){
         perror("fail to close");
        exit(1);
    }

    return 0;
}


8.面向连接的数据传输

除了上面提到的使用read和write外,linux提供了专门用于读写面向连接的套接字的函数。


#include<sys/types.h>
#include<sys/socket.h>
定义函数 int send(int s,const void * msg,int len,unsigned int falgs);
函数说明 send()用来将数据由指定的socket 传给对方主机。参数s为已建立好连接的socket。参数msg指向欲连线的数据内容,参数len则为数据长度。参数flags一般设0,其他数值定义如下
MSG_OOB 传送的数据以out-of-band 送出。
MSG_DONTROUTE 取消路由表查询
MSG_DONTWAIT 设置为不可阻断运作
MSG_NOSIGNAL 此动作不愿被SIGPIPE 信号中断。
返回值 成功则返回实际传送出去的字符数,失败返回-1。错误原因存于errno
错误代码 EBADF 参数s 非合法的socket处理代码。
EFAULT 参数中有一指针指向无法存取的内存空间
ENOTSOCK 参数s为一文件描述词,非socket。
EINTR 被信号所中断。
EAGAIN 此操作会令进程阻断,但参数s的socket为不可阻断。
ENOBUFS 系统的缓冲内存不足
ENOMEM 核心内存不足
EINVAL 传给系统调用的参数不正确。



#include<sys/types.h>
#include<sys/socket.h>
定义函数 int recv(int s,void *buf,int len,unsigned int flags);
函数说明 recv()用来接收远端主机经指定的socket传来的数据,并把数据存到由参数buf 指向的内存空间,参数len为可接收数据的最大长度。
参数 flags一般设0。其他数值定义如下:
MSG_OOB 接收以out-of-band 送出的数据。
MSG_PEEK 返回来的数据并不会在系统内删除,如果再调用recv()会返回相同的数据内容。
MSG_WAITALL强迫接收到len大小的数据后才能返回,除非有错误或
信号产生。
MSG_NOSIGNAL此操作不愿被SIGPIPE信号中断返回值成功则返回接收
到的字符数,失败返回-1,错误原因存于errno中。
错误代码 EBADF 参数s非合法的socket处理代码
EFAULT 参数中有一指针指向无法存取的内存空间
ENOTSOCK 参数s为一文件描述词,非socket。
EINTR 被信号所中断
EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断
ENOBUFS 系统的缓冲内存不足。
ENOMEM 核心内存不足
EINVAL 传给系统调用的参数不正确。

返回值:

大于0:表示成功接收数据,返回值是实际接收的字节数

等于0:表示没有可用的数据或者通信的对端已经结束了发送数据

等于-1:出错



9.面向连接的网络应用程序--服务器端

客户端发送一个字符串,服务器端计算字符串的长度并返回。


//server.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

#define MAX_LINE 100



int main(void)
{
     struct sockaddr_in sin;
     struct sockaddr_in cin;
     int l_fd;
     int c_fd;
     socklen_t len;
     char buf[MAX_LINE];
     char addr_p[INET_ADDRSTRLEN];
     int port = 8000;
     int n;
     
     bzero(&sin, sizeof(sin));
     sin.sin_family = AF_INET; //ipv4
     sin.sin_addr.s_addr = INADDR_ANY; //服务器端可接受任何地址
     sin.sin_port = htons(port);//端口号转化为网络字节序
  
     if((l_fd = socket(AF_INET, SOCK_STREAM, 0))==-1){ //使用tcp建立套接字
        perror("fail to creat soocket");
        exit(1);
     }
  
     if((bind(l_fd, (struct sockaddr *)&sin, sizeof(sin))==-1){//将套接字和地址绑定
    perror("fail to bind");
        exit(1);
     }

     if(listen(l_fd, 10)==-1){ //开始监听连接请求
    perror("fail to listen");
        exit(1);
     }

     printf("waiting .../n");
  
    while(1){//服务器端一般都是死循环
                //接受连接请求,从此函数返回后,就可以真正开始通信了
        if((c_fd = accept(l_fd, (struct sockaddr *) &cin, &len))==-1){
                   perror("fail to accept");
                   exit(1);
                }

        n = recv(c_fd, buf, MAX_LINE,0); //读取客户端传来的数据
                if(n==-1){//读取出错
                   perror("fail to receive");
                   eixt(1);
                }else if(n==0){//通信的另一端已经关闭
                   printf("the connect has been closed/n");
                   close(c_fd);
                   continue;//此次连接处理结束,准备处理下一个连接

        inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p)); //将客户端地址转换为字符串
        printf("client IP is %s, port is %d/n", addr_p, ntohs(sin.sin_port));
            printf("content is : %s/n", buf);
       
        n=strlen(buf);
                sprintf(buf,"%d",n);
                n=send(c_fd,buf,strlen(buf)+1,0);
                if(n==-1){
                  perror("fail to send");
                  exit(1);
                }
      
  

           if(close(c_fd) == -1){
         perror("fail to close");
         exit(1);
        }
        }

    return 0;
}


10.面向连接的网络应用程序--客户端

//client.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

#define MAX_LINE 100
  
int main(int argc, char *argv[])
{
     struct sockaddr_in sin;//服务器的地址
     char buf[MAX_LINE];
     int sfd;
        int port = 8000;//要和服务器端一样才行
     char *str = "test sting"; //默认的字符串
  
     if (argc > 1)
          str = argv[1];//从命令行参数中取得用户输入的串
  
     bzero(&sin, sizeof(sin));
     sin.sin_family = AF_INET;//ipv4
  
     inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
     sin.sin_port = htons(port);
  
      if((s_fd = socket(AF_INET, SOCK_STREAM, 0))==-1){ //使用tcp建立套接字
        perror("fail to creat soocket");
        exit(1);
     }

     if(connect(sfd, (struct sockaddr_in *)&sin, sizeof(sin))==-1){
       perror("fail to connect");
       exit(1);
      }

     n=send(s_fd,str,strlen(str)+1,0);
     if(n==-1){
        perror("fail to send");
        exit(1);
     }

     n=recv(s_fd,buf,MAX_LINE,0);
      if(n==-1){
        perror("fail to receive");
        exit(1);
     }

     printf("the length of the str is: %s/n", buf);

     if(close(s_fd) == -1){
         perror("fail to close");
         exit(1);
        }
   
    return 0;
}



11.无连接的数据传输

 

由于没有建立连接,因此每次发送数据的过程中都要明确指明该数据包的目的地址。在接收数据包时,接收进城可以得到发送该数据包的地址,从而知道该数据包是从哪儿来的。

linux提供了 专门用于对无连接的套接字进行读写的函数。

 

#include < sys/types.h >
#include < sys/socket.h >
定义函数 int sendto ( int s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ;
函数说明 sendto() 用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket,如果利用UDP协议则不需经过连线操作。参数msg指向欲连线的数据内容,参数flags 一般设0,详细描述请参考send()。参数to用来指定欲传送的网络地址,结构sockaddr请参考bind()。参数tolen为sockaddr的结果长度。
返回值 成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。
错误代码 EBADF 参数s非法的socket处理代码。
EFAULT 参数中有一指针指向无法存取的内存空间。
WNOTSOCK canshu s为一文件描述词,非socket。
EINTR 被信号所中断。
EAGAIN 此动作会令进程阻断,但参数s的soket为补课阻断的。
ENOBUFS 系统的缓冲内存不足。
EINVAL 传给系统调用的参数不正确。

 

#include<sys/types.h>
#include<sys/socket.h>
定义函数 int recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);
函数说明 recv()用来接收远程主机经指定的socket 传来的数据,并把数据存到由参数buf 指向的内存空间,参数len 为可接收数据的最大长度。参数flags 一般设0,其他数值定义请参考recv()。参数from用来指定欲传送的网络地址,结构sockaddr 请参考bind()。参数fromlen为sockaddr的结构长度。
返回值 成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。
错误代码 EBADF 参数s非合法的socket处理代码
EFAULT 参数中有一指针指向无法存取的内存空间。
ENOTSOCK 参数s为一文件描述词,非socket。
EINTR 被信号所中断。
EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断。
ENOBUFS 系统的缓冲内存不足
ENOMEM 核心内存不足
EINVAL 传给系统调用的参数不正确。

 

范例:

//udpserver.c

#include < sys/types.h >
#include < sys/socket.h >
# include <netinet.in.h>
#include <arpa.inet.h>
#define PORT 2345 /*使用的port*/
main(){
int sockfd,len;
struct sockaddr_in addr;
char buffer[256];
/*建立socket*/
if(sockfd=socket (AF_INET,SOCK_DGRAM,0))<0){
perror (“socket”);
exit(1);
}
/*填写sockaddr_in 结构*/
bzero ( &addr, sizeof(addr) );
addr.sin_family=AF_INET;
addr.sin_port=htons(PORT);
addr.sin_addr=hton1(INADDR_ANY) ;
if (bind(sockfd, &addr, sizeof(addr))<0){
perror(“connect”);
exit(1);
}
while(1){
bezro(buffer,sizeof(buffer));
len = recvfrom(socket,buffer,sizeof(buffer), 0 , &addr
&addr_len);
/*显示client端的网络地址*/
printf(“receive from %s/n “ , inet_ntoa( addr.sin_addr));
/*将字串返回给client端*/
sendto(sockfd,buffer,len,0,&addr,addr_len);”
}
}

 

 

//udpclient.c

#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/typs.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define PORT 2345
#define SERVER_IP “127.0.0.1”
main()
{
int s,len;
struct sockaddr_in addr;
int addr_len =sizeof(struct sockaddr_in);
char buffer[256];
/* 建立socket*/
if((s = socket(AF_INET,SOCK_DGRAM,0))<0){
perror(“socket”);
exit(1);
}
/* 填写sockaddr_in*/
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(SERVER_IP);
while(1){
bzero(buffer,sizeof(buffer));
/* 从标准输入设备取得字符串*/
len =read(STDIN_FILENO,buffer,sizeof(buffer));
/* 将字符串传送给server端*/
sendto(s,buffer,len,0,&addr,addr_len);
/* 接收server端返回的字符串*/
len = recvfrom(s,buffer,sizeof(buffer),0,&addr,&addr_len);
printf(“receive: %s”,buffer);
}
}

 

 

原创粉丝点击