现在的位置: 首页 > 综合 > 正文

socket通信之最简单的socket通信

2013年10月28日 ⁄ 综合 ⁄ 共 4421字 ⁄ 字号 评论关闭

套接字有三种类型

流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)及原始套接字。

1.流式套接字提供面向连接、可靠的数据传输服务,数据按字节流、按顺序收发,保证在传输过程中无丢失、无冗余。TCP协议支持该套接字。

2.数据报套接字,提供面向无连接的服务,数据收发无序,不能保证数据的准确到达。UDP协议支持该套接字。

3.原始套接字原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。

重要的几个结构体:

1.sockaddr

struct sockaddr
{
        unsigned short sa_family; /* address族, AF_xxx */
        char sa_data[14]; /* 14 bytes的协议地址 */
};

sa_family 一般来说,都是“AFINET”。
sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一切的。

由于在设置上面比较麻烦,所以有了一个更清晰的结构体数据

2.struct sockaddr_in

注:“in” 代表 “Internet”

struct sockaddr_in 
{
        short int sin_family; /* Internet地址族 */
        unsigned short int sin_port; /* 端口号 */
        struct in_addr sin_addr; /* Internet地址 */
        unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/
};

3.struct in_addr (Internet地址)

struct in_addr
{
 unsigned long s_addr;
};

一些函数:

1.socket

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain , int type , int protocol);

说明:

domain 需要被设置为“AF_INET”;

type为套接字类型;

protocol为协议一般设置为0

2.bind()

#include <sys/types.h>
#include <sys/socket.h>
int bind (int sockfd , struct sockaddr *my_addr , int addrlen) ;
参数说明:
sockfd 是由socket()函数返回的套接字描述符。
my_addr 是一个指向struct sockaddr 的指针,包含有关你的地址的信息:名称、端口和IP 地址,可以将struct sockaddr_in结构体强制类型转换传入。
addrlen 可以设置为sizeof(struct sockaddr)。

3.connect()

#include <sys/types.h>
#include <sys/socket.h>
int connect (int sockfd, struct sockaddr *serv_addr, int addrlen);
参数说明:

sockfd :套接字文件描述符,由socket()函数返回的。
serv_addr 是一个存储远程计算机的IP 地址和端口信息的结构。
addrlen 应该是sizeof(struct sockaddr)。

4.listen()

#include <sys/socket.h>
int listen(int sockfd, int backlog);
参数说明:

sockfd 是一个套接字描述符,由socket()系统调用获得。
backlog 是未经过处理的连接请求队列可以容纳的最大数目。

5.accept()

#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen);
参数说明:

sockfd 是正在listen() 的一个套接字描述符。
addr 一般是一个指向struct sockaddr_in 结构的指针;里面存储着远程连接过来的计算机的信息(比如远程计算机的IP 地址和端口)。
addrlen 是一个本地的整型数值,在它的地址传给accept() 前它的值应该是sizeof(struct sockaddr_in);accept()不会在addr 中存储多余addrlen bytes 大小的数据。如果accept()函数在addr 中存储的数据量不足addrlen,则accept()函数会改变addrlen 的值来反应这个情况。

注:调用成功后返回一个标识符,被send或recv用来进行数据的接收和发送

6.send()

#include <sys/types.h>
#include <sys/socket.h>
int send(int sockfd, const void *msg, int len, int flags);
参数说明:
sockfd 是代表你与远程程序连接的套接字描述符。
msg 是一个指针,指向你想发送的信息的地址。
len 是你想发送信息的长度。
flags 发送标记。一般都设为0(你可以查看send 的man pages 来获得其他的参数值并且明白各个参数所代表的含义,很多时候只要你手不懒,通过linux的man命令可以获得很多详细的说明,另外很多书籍或者博客信息也都是man的中文翻译)。

7.recv()

#include <sys/types.h>
#include <sys/socket.h>
int recv(int sockfd, void *buf, int len, unsigned int flags);
参数说明:
sockfd 是你要读取数据的套接字描述符。
buf 是一个指针,指向你能存储数据的内存缓存区域。
len 是缓存区的最大尺寸。
flags 是recv() 函数的一个标志,一般都为0

到此你可以写出一个简单的c/s模式的通信来了。

c/s模式是面向连接的demo

server端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define MAXLINE 4096
int main(int argc, char** argv)
{    
        int    listenfd, connfd;    
        struct sockaddr_in     servaddr;    
        char    buff[4096];    
        int     n;    
        if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
        {    
                printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);    
                exit(0);    
        }    
        memset(&servaddr, 0, sizeof(servaddr));    
        servaddr.sin_family = AF_INET;    
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    
        servaddr.sin_port = htons(6666);    
        if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
        {    
                printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);    
                exit(0);    
        }    
        if( listen(listenfd, 10) == -1)
        {    
                printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);    
                exit(0);    
        }      
        printf("======waiting for client's request======\n");    
        while(1)
        {    
                if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
                {        
                        printf("accept socket error: %s(errno: %d)",strerror(errno),errno);        
                        continue;    
                }    
                n = recv(connfd, buff, MAXLINE, 0);    
                buff[n] = '\0';    
                printf("recv msg from client: %s\n", buff);    
                close(connfd);    
        }    
        close(listenfd);
}

client端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define MAXLINE 4096
int main(int argc, char** argv)
{    
        int    sockfd, n;    
        char    recvline[4096], sendline[4096];    
        struct sockaddr_in    servaddr;    
        if( argc != 2)
        {    
                printf("usage: ./client <ipaddress>\n");    
                exit(0);    
        }    
        if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {   
                printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);    
                exit(0);    
        }    
        memset(&servaddr, 0, sizeof(servaddr));    
        servaddr.sin_family = AF_INET;    
        servaddr.sin_port = htons(6666);    
        if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
        {    
                printf("inet_pton error for %s\n",argv[1]);    
                exit(0);    
        }    
        if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
        {    
                printf("connect error: %s(errno: %d)\n",strerror(errno),errno);    
                exit(0);    
        }    
        printf("send msg to server: \n");   
        fgets(sendline, 4096, stdin);    
        if( send(sockfd, sendline, strlen(sendline), 0) < 0)    
        {    
                printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);    
                exit(0);    
        }   
        close(sockfd);    
        exit(0);
}

 

抱歉!评论已关闭.