linux 下socket编程

来源:互联网 发布:康佳电视直播的软件 编辑:程序博客网 时间:2024/05/16 09:10

socket用于服务端和客户端之间的通信。

服务端的流程:

1. 取得文件描述符——socket()

#include<sys/socket.h>

int  socket(int domain,int type,int protocol);

int  domain: 

unix domain:填AF_UNIX,允许在内核中同一主机上的应用程序之间进行通信;路径名。

IPv4 domain:填AF_INET,通过IPv4网络连接起来进行通信;32位ipv4地址和16位端口号。

IPv6 domain:填AF_INET,通过IPv4网络连接起来进行通信;128位ipv6地址和16位端口号。

int  type:

流SOCKET(TCP):填SOCK_STREAM

 数据报SOCKET(UDP):填SOCK_DGRAM

int protocol:

0即可。protocol是与特定的地址家族相关的协议,如果指定为0,那么系统就会根据地址格式和套接类别,自动选择一个合适的协议.这是推荐使用的一种选择协议的方法.

返回值:

如果socket函数调用成功,他就会返回一个新的socket数据类型的套接字描述符;如果调用失败,这个函数返回一个INVALID_SOCKET值,错误信息可以通过WSAGetLastError函数返回.

2. 定义socket_in和相关内容。

struct sockaddr_in
{
short sin_family;/*Addressfamily一般来说AF_INET(地址族)PF_INET(协议族)*/填写AF_INET/AF_INET6

unsignedshort sin_port;/*Portnumber(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
 
struct in_addr sin_addr;/*Internetaddress*/
 
unsignedchar sin_zero[8];/*Samesizeasstructsockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/
 
};
typedef struct in_addr
{
unsigned long s_addr;
};
htons() 是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为:高位字节存放在内存的低地址处。

#include <arpa/inet.h>
htons()将主机数转换成无符号长整形的网络字节顺序。一个32位数从主机字节顺序转换成网络字节顺序
INADDR_ANY指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值


3. bind()系统调用将socket绑定到一个地址上。

#include<sys/socket.h>

int bind(int  sockfd,const struct sockaddr *addr,socklen_t addrlen);     //sockaddr_in 与 sockaddr 结构上等价的

int sockfd 就是在socket()后返回的值

const sockadd* add 就是2中准备的sockaddr_in。

socklen_t addrlen是sockaddr_in的长度,使用sizeof()函数即可。

返回值:成功,返回0;出错,返回-1

4.监听接入连接:listen()

#include<sys/socket.h>

int listen(int sockfd,int backlog);

int backlog=已连接队列大小+未连接队列大小

返回值:成功,返回0;出错,返回-1

5.accept()接受连接

#include<sys/socket/h>

int  accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);

与blind参数基本一致,但是此处是新的addr

返回值:成功,返回一个新的文件描述符


6.recv() 接受数据

int recv( SOCKET s, char FAR *buf, int len, int flags);   

    不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;

    第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;

    第三个参数指明buf的长度;

    第四个参数一般置0。

    这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时,

    (1)recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,

    (2)如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以 在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),

7.send()发送数据

int send( SOCKET s, const char FAR *buf, int len, int flags );  

    不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

    该函数的第一个参数指定发送端套接字描述符;

    第二个参数指明一个存放应用程序要发送数据的缓冲区;

    第三个参数指明实际要发送的数据的字节数;

    第四个参数一般置0。 

    这里只描述同步Socket的send函数的执行流程。当调用该函数时,

   (1)send先比较待发送数据的长度len和套接字s的发送缓冲的长度, 如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;

   (2)如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len

   (3)如果len大于剩余空间大小,send就一直等待协议把s的发送缓冲中的数据发送完

   (4)如果len小于剩余 空间大小,send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)。

   如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。

   要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执 行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回 SOCKET_ERROR)

8.close()终止连接

close(sockfd);

客户端:

1.取得文件描述符——socket()

2.定义socket_in和相关内容。

3.connect()连接到对等的socket

#include<sys/socket.h>

int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen)

返回值:成功,返回0;出错,返回-1

4.send()发送数据

5.close()终止连接

close(sockfd);

服务器端

#include <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <sys/shm.h>#define MYPORT  8887#define QUEUE   20#define BUFFER_SIZE 1024int main(){    ///定义sockfd    int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);    ///定义sockaddr_in    struct sockaddr_in server_sockaddr;    server_sockaddr.sin_family = AF_INET;    server_sockaddr.sin_port = htons(MYPORT);    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);    ///bind,成功返回0,出错返回-1    if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)    {        perror("bind");        exit(1);    }    ///listen,成功返回0,出错返回-1    if(listen(server_sockfd,QUEUE) == -1)    {        perror("listen");        exit(1);    }    ///客户端套接字    char buffer[BUFFER_SIZE];    struct sockaddr_in client_addr;    socklen_t length = sizeof(client_addr);    ///成功返回非负描述字,出错返回-1    int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);    if(conn<0)    {        perror("connect");        exit(1);    }    while(1)    {        memset(buffer,0,sizeof(buffer));        int len = recv(conn, buffer, sizeof(buffer),0);        if(strcmp(buffer,"exit\n")==0)            break;        fputs(buffer, stdout);        send(conn, buffer, len, 0);    }    close(conn);    close(server_sockfd);    return 0;}

客户端

#include <sys/types.h>#include <sys/socket.h>#include <stdio.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <sys/shm.h>#define MYPORT  8887#define BUFFER_SIZE 1024int main(){    ///定义sockfd    int sock_cli = socket(AF_INET,SOCK_STREAM, 0);    ///定义sockaddr_in    struct sockaddr_in servaddr;    memset(&servaddr, 0, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(MYPORT);  ///服务器端口    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  ///服务器ip    ///连接服务器,成功返回0,错误返回-1    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)    {        perror("connect");        exit(1);    }    char sendbuf[BUFFER_SIZE];    char recvbuf[BUFFER_SIZE];    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)    {        send(sock_cli, sendbuf, strlen(sendbuf),0); ///发送        if(strcmp(sendbuf,"exit\n")==0)            break;        recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收        fputs(recvbuf, stdout);        memset(sendbuf, 0, sizeof(sendbuf));        memset(recvbuf, 0, sizeof(recvbuf));    }    close(sock_cli);    return 0;}


0 0