`
gstarwd
  • 浏览: 1525351 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

socket编程接口调用函数以及示例(C实现)

阅读更多

socket()


我们使用系统调用 socket() 来获得文件描述符:
#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type,int protocol);
第一个参数 domain 设置为 “AF_INET”
第二个参数是套接口的类型: SOCK_STREAM
SOCK_DGRAM
。第三个参数设置为 0
系统调用 socket() 只返回一个套接口描述符,如果出错,则返回 -1  

bind()

一旦你有了一个套接口以后,下一步就是把套接口绑定到本地计算机的某一个端口上。但如果你只想使用 connect() 则无此必要。
下面是系统调用 bind() 的使用方法:
#include<sys/types.h>
#include<sys/socket.h>
intbind(int sockfd,struct sockaddr*my_addr,int addrlen);
第一个参数 sockfd 是由 socket() 调用返回的套接口文件描述符。
第二个参数 my_addr 是指向数据结构 sockaddr 的指针。数据结构 sockaddr 中包括了关于你的地址、端口和 IP 地址的信息。
第三个参数 addrlen 可以设置成 sizeof(structsockaddr)
下面是一个例子:

#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#defineMYPORT3490
main()
{
int sockfd;
struct sockaddr_inmy_addr;
sockfd=socket(AF_INET,SOCK_STREAM,0);/*do someerror checking!*/
my_addr.sin_family=AF_INET;/*hostbyteorder*/
my_addr.sin_port=htons(MYPORT);/*short,network byte order*/
my_addr.sin_addr.s_addr=inet_addr("132.241.5.10");
bzero(&(my_addr.sin_zero),8);/*zero the rest of the struct*/
/*don't forget your error checking for bind():*/
bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));
...
 

如果出错, bind() 也返回 -1
如果你使用 connect() 系统调用,那么你不必知道你使用的端口号。当你调用 connect() 时,它检查套接口是否已经绑定,如果没有,它将会分配一个空闲的端口。

connect()

系统调用 connect() 的用法如下:
#include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd,struct sockaddr* serv_addr,int addrlen);
第一个参数还是套接口文件描述符,它是由系统调用 socket() 返回的。
第二个参数是 serv_addr 是指向数据结构 sockaddr 的指针,其中包括目的端口和 IP 地址。
第三个参数可以使用 sizeof(structsockaddr) 而获得。
下面是一个例子:
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#defineDEST_IP"132.241.5.10"
#defineDEST_PORT23
main()
{
intsockfd;
structsockaddr_indest_addr;/*will hold the destination addr*/
sockfd=socket(AF_INET,SOCK_STREAM,0);/*do some error checking!*/
dest_addr.sin_family=AF_INET;/*hostbyteorder*/
dest_addr.sin_port=htons(DEST_PORT);/*short,network byte order*/
dest_addr.sin_addr.s_addr=inet_addr(DEST_IP);
bzero(&(dest_addr.sin_zero),8);/*zero the rest of the struct*/
/*don'tforgettoerrorchecktheconnect()!*/
connect(sockfd,(structsockaddr*)&dest_addr,sizeof(struct sockaddr));
...
同样,如果出错, connect() 将会返回 -1

listen()


如果你希望不连接到远程的主机,也就是说你希望等待一个进入的连接请求,然后再处理它们。这样,你通过首先调用 listen() ,然后再调用 accept() 来实现。
系统调用 listen() 的形式如下:
intl isten(int sockfd,int backlog);
第一个参数是系统调用 socket() 返回的套接口文件描述符。
第二个参数是进入队列中允许的连接的个数。进入的连接请求在使用系统调用 accept() 应答之前要在进入队列中等待。这个值是队列中最多可以拥有的请求的个数。大多数系统的缺省设置为 20 。你可以设置为 5 或者 10 。当出错时, listen() 将会返回 -1 值。
当然,在使用系统调用 listen() 之前,我们需要调用 bind() 绑定到需要的端口,否则系统内核将会让我们监听一个随机的端口。所以,如果你希望监听一个端口,下面是应该使用的系统调用的顺序:
socket();
bind();
listen();
/*accept()goeshere*/ 

accept()


系统调用 accept() 比较起来有点复杂。在远程的主机可能试图使用 connect() 连接你使用
listen()
正在监听的端口。但此连接将会在队列中等待,直到使用 accept() 处理它。调用 accept()
之后,将会返回一个全新的套接口文件描述符来处理这个单个的连接。这样,对于同一个连接
来说,你就有了两个文件描述符。原先的一个文件描述符正在监听你指定的端口,新的文件描
述符可以用来调用 send() recv()
调用的例子如下:
#include<sys/socket.h>
intaccept(intsockfd,void*addr,int*addrlen);
第一个参数是正在监听端口的套接口文件描述符。第二个参数 addr 是指向本地的数据结构
sockaddr_in
的指针。调用 connect() 中的信息将存储在这里。通过它你可以了解哪个主机在哪个
端口呼叫你。第三个参数同样可以使用 sizeof(structsockaddr_in) 来获得。
如果出错, accept() 也将返回 -1 。下面是一个简单的例子:

#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#defineMYPORT3490/*theportuserswillbeconnectingto*/
#defineBACKLOG10/*howmanypendingconnectionsqueuewillhold*/
main()
{
intsockfd,new_fd;/*listenonsock_fd,newconnectiononnew_fd*/
structsockaddr_inmy_addr;/*myaddressinformation*/
structsockaddr_intheir_addr;/*connector'saddressinformation*/
intsin_size;
sockfd=socket(AF_INET,SOCK_STREAM,0);/*dosomeerrorchecking!*/
my_addr.sin_family=AF_INET;/*hostbyteorder*/
my_addr.sin_port=htons(MYPORT);/*short,networkbyteorder*/
my_addr.sin_addr.s_addr=INADDR_ANY;/*auto-fillwithmyIP*/
bzero(&(my_addr.sin_zero),8);/*zerotherestofthestruct*/
/*don'tforgetyourerrorcheckingforthesecalls:*/
bind(sockfd,(structsockaddr*)&my_addr,sizeof(structsockaddr));
listen(sockfd,BACKLOG);
sin_size=sizeof(structsockaddr_in);
new_fd=accept(sockfd,&their_addr,&sin_size);
...
 


下面,我们将可以使用新创建的套接口文件描述符 new_fd 来调用 send() recv()

send() recv()


系统调用 send() 的用法如下:
int send(int sockfd,const void* msg,int len,int flags);
第一个参数是你希望给发送数据的套接口文件描述符。它可以是你通过 socket() 系统调用返回的,也可以是通过 accept() 系统调用得到的。
第二个参数是指向你希望发送的数据的指针。
第三个参数是数据的字节长度。第四个参数标志设置为 0
下面是一个简单的例子:
char*msg="Beejwashere!";
intlen,bytes_sent;
..
len=strlen(msg);
bytes_sent=send(sockfd,msg,len,0);
...
系统调用 send() 返回实际发送的字节数,这可能比你实际想要发送的字节数少。如果返回的字节数比要发送的字节数少,你在以后必须发送剩下的数据。当 send() 出错时,将返回 -1
系统调用 recv() 的使用方法和 send() 类似:
int recv(int sockfd,void* buf,int len,unsigned int flags);
第一个参数是要读取的套接口文件描述符。
第二个参数是保存读入信息的地址。
第三个参数是缓冲区的最大长度。第四个参数设置为 0
系统调用 recv() 返回实际读取到缓冲区的字节数,如果出错则返回 -1
这样使用上面的系统调用,你可以通过数据流套接口来发送和接受信息。  

sendto() recvfrom()


因为数据报套接口并不连接到远程的主机上,所以在发送数据包之前,我们必须首先给出目的地址,请看:
int sendto(int sockfd,const void* msg,int len,unsigned int flags,
conststruct sockaddr*to,inttolen);
除了两个参数以外,其他的参数和系统调用 send() 时相同。
参数 to 是指向包含目的 IP 地址和端口号的数据结构 sockaddr 的指针。
参数 tolen 可以设置为 sizeof(structsockaddr)
系统调用 sendto() 返回实际发送的字节数,如果出错则返回 -1
系统调用 recvfrom() 的使用方法也和 recv() 的十分近似:
int recvfrom(int sockfd,void* buf,int len,unsigned int flags
struct sockaddr* from,int* fromlen);
参数 from 是指向本地计算机中包含源 IP 地址和端口号的数据结构 sockaddr 的指针。
参数 fromlen 设置为 sizeof(struct sockaddr)
系统调用 recvfrom() 返回接收到的字节数,如果出错则返回 -1

close() shutdown()


你可以使用 close() 调用关闭连接的套接口文件描述符:
close(sockfd);
这样就不能再对此套接口做任何的读写操作了。
使用系统调用 shutdown() ,可有更多的控制权。它允许你在某一个方向切断通信,或者切断双方的通信:
int shutdown(int sockfd,int how);
第一个参数是你希望切断通信的套接口文件描述符。第二个参数 how 值如下:
0—Furtherreceivesaredisallowed
1—Furthersendsaredisallowed
2—Furthersendsandreceivesaredisallowed(likeclose())
shutdown()
如果成功则返回 0 ,如果失败则返回 -1

getpeername()


这个系统的调用十分简单。它将告诉你是谁在连接的另一端:
#include<sys/socket.h>
int getpeername(int sockfd,struct sockaddr* addr,int* addrlen);
第一个参数是连接的数据流套接口文件描述符。
第二个参数是指向包含另一端的信息的数据结构 sockaddr 的指针。
第三个参数可以设置为 sizeof(structsockaddr)
如果出错,系统调用将返回 -1
一旦你获得了它们的地址,你可以使用 inet_ntoa() 或者 gethostbyaddr() 来得到更多的信息。

gethostname()


系统调用 gethostname() 比系统调用 getpeername() 还简单。它返回程序正在运行的计算机的名字。系统调用 gethostbyname() 可以使用这个名字来决定你的机器的 IP 地址。
下面是一个例子:
#include<unistd.h>
int gethostname(char*hostname,size_tsize);
如果成功, gethostname 将返回 0 。如果失败,它将返回 -1  

SOCKET C 程序代码

Makefile 文件

s: app_service.c

       gcc -o s app_service.c

c: app_client.c

       gcc -o c app_client.c

 

app_client.c 文件

//客户端程序代码如下:

#include<stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <netdb.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#define SERVPORT 3333

#define MAXDATASIZE 100              // 每次最大数据传输量

 

main(int argc, char *argv[])

{

       int sockfd, recvbytes;

       char buf[MAXDATASIZE];

       struct hostent *host;

       struct sockaddr_in serv_addr;

 

       if (argc < 2) {

              fprintf(stderr,"Please enter the server's hostname!\n");

              exit(1);

       }

       if ((host = gethostbyname(argv[1])) == NULL) {

              herror("gethostbyname出错!");

              exit(1);

       }

       if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

              perror("socket创建出错!");

              exit(1);

       }

       serv_addr.sin_family = AF_INET;

       serv_addr.sin_port = htons(SERVPORT);

       serv_addr.sin_addr = *((struct in_addr *)host->h_addr);

       bzero(&(serv_addr.sin_zero), 8);

       if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {

              perror("connect出错!");

              exit(1);

       }

       if ((recvbytes = recv(sockfd, buf, MAXDATASIZE, 0)) ==-1) {

              perror("recv出错!");

              exit(1);

       }

       buf[recvbytes] = '\0';

       printf("Received: %s",buf);

       close(sockfd);

}

 

/*

    客户端程序首先通过服务器域名获得服务器的IP地址,然后创建一个socket,调用connect函数与服务器建立连接,连接成功之后接收从服务器发送过来的数据,最后关闭socket。

  函数gethostbyname()是完成域名转换的。由于IP地址难以记忆和读写,所以为了方便,人们常常用域名来表示主机,这就需要进行域名和IP地址的转换。函数原型为:

  struct hostent *gethostbyname(const char *name);

  函数返回为hosten的结构类型,它的定义如下:

  struct hostent {

       char *h_name; // 主机的官方域名

       char **h_aliases; // 一个以NULL结尾的主机别名数组

       int h_addrtype; // 返回的地址类型,在Internet环境下为AF-INET

       int h_length; // 地址的字节长度

       char **h_addr_list; // 一个以0结尾的数组,包含该主机的所有地址

    };

  #define h_addr h_addr_list[0] //在h-addr-list中的第一个地址

  当 gethostname()调用成功时,返回指向struct hosten的指针,当调用失败时返回-1。当调用gethostbyname时,你不能使用perror()函数来输出错误信息,

应该使用herror()函数来输出。

 

  无连接的客户/服务器程序的在原理上和连接的客户/服务器是一样的,两者的区别在于无连接的客户/服务器中的客户一般不需要建立连接,而且在发送接收

数据时,需要指定远端机的地址。

 

*/
 

app_service.c 文件

/*

面向连接的Socket实例

  代码实例中的服务器通过socket连接向客户端发送字符串"Hello, you are connected!"。只要在服务器上运行该服务器软件,在客户端运行客户软件,客户端就会收到该字符串。

  该服务器软件代码如下:

*/

                                                                                                                                              

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/wait.h>

 

#define SERVPORT 3333     // 服务器监听端口号

#define BACKLOG 10 // 最大同时连接请求数

 

main()

{

       int sockfd, client_fd;            // sock_fd:监听socket;client_fd:数据传输socket

       struct sockaddr_in my_addr;        // 本机地址信息

       struct sockaddr_in remote_addr; // 客户端地址信息

       int sin_size;

 

       if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

              perror("socket创建出错!"); exit(1);

       }

       my_addr.sin_family = AF_INET;

       my_addr.sin_port = htons(SERVPORT);

       my_addr.sin_addr.s_addr = INADDR_ANY;

       bzero(&(my_addr.sin_zero), 8);

       if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {

              perror("bind出错!");

              exit(1);

       }

       if (listen(sockfd, BACKLOG) == -1) {

              perror("listen出错!");

              exit(1);

       }

       while(1) {

              sin_size = sizeof(struct sockaddr_in);

              if ((client_fd = accept(sockfd, (void *)&remote_addr, &sin_size)) == -1) {

                     perror("accept出错");

                     continue;

              }

              printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));

              if (!fork()) { /* 子进程代码段 */

                     if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1) {

                            perror("send出错!");

                            close(client_fd);

                            exit(0);

                     }

              }

              close(client_fd);

       }

}

/*

 服务器的工作流程是这样的:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,然后调用 listen在相应的socket上监听,当accpet接收到一个连接服务请求时,将生成一个新的socket。服务器显示该客户机的IP地址,并通过新的socket向客户端发送字符串"Hello,you are connected!"。最后关闭该socket。

  代码实例中的fork()函数生成一个子进程来处理数据传输部分,fork()语句对于子进程返回的值为0。所以包含fork函数的if语句是子进程代码部分,它与if语句后面的父进程代码部分是并发执行的。

*/
分享到:
评论

相关推荐

    socket编程接口调用函数以及示例[总结].pdf

    Socket编程接口是软件开发中的核心部分,特别是在网络通信领域。它提供了一种标准的方法来创建、连接和通信两个或多个通过网络连接的进程。在本文中,我们将深入探讨`socket()`、`bind()`和`connect()`这三个关键的...

    Linux下的Socket编程实例(阻塞和非阻塞)

    Linux下的Socket编程实例是使用 C/C++ 语言实现的,通过使用 socket 函数创建一个 Socket,然后调用 bind 函数将其与本机地址以及一个本地端口号绑定,最后调用 listen 函数在相应的 socket 上监听。使用 fork 函数...

    Socket编程例子

    Socket编程是计算机网络通信中的重要概念,主要用于实现进程间的网络通信。在本示例中,我们探讨的是如何使用Socket进行程序间的交互。Socket可以被看作是两台计算机之间的通信端点,允许它们通过网络交换数据。下面...

    c语言SOCKET编程指南.pdf

    19. 简单的服务器:简单的服务器是SOCKET编程中的一个重要示例,用于描述服务器端的实现。 20. 简单的客户端:简单的客户端是SOCKET编程中的一个重要示例,用于描述客户端的实现。 21. 数据报套接字 Socket:数据...

    windows下socket编程示例

    这里的"windows下socket编程示例"是指使用C语言基础的Socket接口编写在Windows操作系统下的网络应用程序,而不是基于MFC(Microsoft Foundation Classes)库的CSocket类。CSocket是MFC对Winsock API的封装,而这里...

    Windows环境下socket编程(C语言编写)

    在Windows环境下进行Socket编程,通常使用C语言进行底层网络通信的实现,因为它提供了灵活且高效的方式来操作网络套接字。本示例中的"Windows环境下socket编程(C语言编写)"是一个简单的服务器-客户端通信模型,它...

    C语言Socket简单编程指南

    Socket编程通常涉及到了解套接字(Socket)的基本概念、网络理论、各种网络编程函数以及如何处理IP地址等问题。以下是从提供的文件信息中提炼出的知识点: ### 什么是Socket Socket是应用程序进行网络通讯的一种...

    c语言socket编程指南.pdf

    综上所述,《C语言socket编程指南》是一份面向C语言程序员的网络编程参考资料,涵盖了从基础API调用到复杂网络协议实现的关键概念和函数。通过学习该指南,读者将能掌握如何使用C语言进行网络通信,并能够开发出能够...

    VC学习笔记-基于TCP的socket编程

    ### 基于TCP的Socket编程在VC中的应用与实现 #### 一、知识点概览 在VC(Visual C++)环境下进行网络编程时,基于TCP的socket编程是实现客户端与服务器之间通信的重要方式之一。本文将从初始化、创建socket、绑定...

    Socket编程指南及示例程序

    本文将深入探讨Socket编程的基本概念、机制、头文件、库文件以及DLL,同时结合TCP/IP和UDP协议,提供详尽的示例程序以加深理解。 首先,Socket是一种接口,它允许程序员通过API(应用程序编程接口)与操作系统交互...

    C#异步socket接收组件和调用示例

    在.NET编程环境中,C#语言提供了...总结,C#异步socket接收组件和调用示例旨在教授如何使用异步Socket进行高效的数据通信,通过理解异步编程原理、回调机制以及数据处理流程,开发者可以构建出稳定且高性能的网络应用。

    Socket编程实现聊天工具

    在本项目中,我们利用Socket编程实现了一个简单的聊天工具,这个工具是基于C++语言,并使用Microsoft Visual Studio 2008作为开发环境。对于初学者来说,这是一个很好的实践项目,可以帮助理解Socket的工作原理和...

    网络socket 编程指南

    Socket,作为网络通信的基础接口,是实现进程间、机器间通信的关键工具。本书旨在帮助开发者理解和掌握如何利用Socket进行高效、稳定、可靠的网络应用开发。 1. Socket基础: - Socket的定义:Socket是操作系统...

    C++socket编程实例

    在IT领域,网络通信是不可或缺的一部分,而C++作为强大的编程语言,提供了丰富的库支持进行网络...压缩包中的"**C++Socket编程**"文件可能包含了详细的代码示例和步骤解析,对于学习和理解C++ socket编程非常有帮助。

    socket编程实现通信

    Socket编程是网络编程的核心部分,它提供了一种标准的接口,使得进程间的网络通信变得更加简单。在本场景中,我们关注的是如何通过Socket实现客户端(Client)与服务器(Server)之间的单向通信。以下是关于Socket...

    windows下简单SOCKET编程

    Winsock是Windows Socket接口的简称,它是Microsoft Windows对Berkeley Sockets API的实现,为开发者提供了跨平台的网络通信能力。本教程将围绕如何在Windows下进行基本的SOCKET编程展开。 首先,你需要了解SOCKET...

    socket 编程

    Socket编程是计算机网络通信的核心技术之一,特别是在iOS开发中,Objective-C语言的Socket实现对于构建网络应用程序至关重要。本文将深入探讨Socket编程的基本概念、工作原理以及如何在Objective-C中进行客户端和...

    windows下的socket编程

    在Windows环境下进行C语言的Socket编程,主要是为了实现网络通信,让不同的计算机通过网络进行数据交换。Socket编程是网络编程的基础,它提供了一种标准的接口,使得开发者能够方便地建立网络连接,发送和接收数据。...

Global site tag (gtag.js) - Google Analytics