socket网络编程的相关内容

什么是套接字?

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Internet 套接字的类型

套接字一般分为三种类型:

①流式套接字(SOCK--STREAM):该类套接字提供了面向连接的、可靠的、数据无错并且无重复的数据发送服务。而且发送的数据是按顺序接收的。所有利用该套接字进行传递的数据均被视为连续的字节流的并且无长度限制。这对数据的稳定性、正确性和发送/接受顺序要求严格的应用十分适用,TCP使用该类接口。

②数据报式套接字(SOCK--DGRAM):数据报式套接字提供了面向无连接的服务,不提供正确性检查,也不保证各数据包的发送顺序,因此,可能出现数据的重发、丢失等现象,并且接收顺序由具体路由决定。然而,与流式套接字相比,使用数据报式套接字对网络线路占用率较低。在TCP月P协议组中,UDP使用该类套接字。

③原始套接字(SOCK--RAw):该套接字一般不会出现在高级网络接口的现中,因为它是直接针对协议的较低层(如IP、TCP、UDP等)直接访问的。用于检验新的协议实现或访问现有服务中配置的新设备,使用原始套接字存在络应用程序的兼容性问题,所以一般不推荐使用原始套接字。

socket描述符

>>>socket描述符。它的类型: int

<span style="font-size:14px;">struct sockaddr_in {
   short int sin_family; /* 通信类型 */
   unsigned short int sin_port; /* 端口 */
   struct in_addr sin_addr; /* Internet 地址 */
   unsigned char sin_zero[8]; /* 与sockaddr结构的长度相同*/
   }; </span>
<span style="font-size:14px;"> struct in_addr {
   unsigned long s_addr;
   };
</span>

>>>你声明 "ina" 是数据结构 struct sockaddr_in 的实例,那么 "ina.sin_addr.s_addr" 就储 存4字节的 IP 地址(使用网络字节顺序)。

>>>>sin_zero (它被加入到这个结构,并且长度和 struct sockaddr 一样) 应该使用函数 bzero() 或 memset() 来全部置零。

struct sockaddr {   

unsigned short sa_family; /* 地址家族, AF_xxx */   

char sa_data[14]; /*14字节协议地址*/   

};

>>>sin_port和 sin_addr 必须是网络字节顺序 (Network Byte Order)!

字节转换

能够转换两种类型: short (两个字节)和 long (四个字节)。这个函 数对于变量类型 unsigned 也适用。假设你想将 short 从本机字节顺序转 换为网络字节顺序。用 "h" 表示 "本机 (host)",接着是 "to",然后用 "n" 表 示 "网络 (network)",最后用 "s" 表示 "short": h-to-n-s, 或者 htons() ("Host to Network
Short")。

    <span style="font-size:14px;">htons()--"Host to Network Short"
  htonl()--"Host to Network Long"
  ntohs()--"Network to Host Short"
  ntohl()--"Network to Host Long"</span>

>>>你也许会想到:我的 68000 机器已经使用了网络字节顺序,我没有必要去调用 htonl() 转换 IP 地址。你可能是对的,但是当你移植你的程序到别的机器 上的时候,你的程序将失败。可移植性!这里是 Unix 世界!记住:在你将数据放到网络上的时候,确信它们是网络字节顺序的。

>>>为什么在数据结构 struct sockaddr_in 中, sin_addr 和 sin_port 需要转换为网络字节顺序,而sin_family 需不需要呢? 答案是: sin_addr 和 sin_port 分别封装在包的 IP 和 UDP 层。因此,它们必须要 是网络字节顺序。但是 sin_family 域只是被内核 (kernel) 使用来决定在数 据结构中包含什么类型的地址,所以它必须是本机字节顺序。同时,
sin_family 没有发送到网络上,它们可以是本机字节顺序。

IP 地址处理

假设你已经有了一个sockaddr_in结构体ina,你有一个IP地址"132.241.5.10"要储存在其中,你就要用到函数inet_addr(),将IP地址从 点数格式转换成无符号长整型。使用方法如下:

<span style="font-size:14px;">ina.sin_addr.s_addr = inet_addr("132.241.5.10"); </span>

inet_addr()返回的地址已经是网络字节格式,所以你无需再调用 函数htonl()。 当inet_addr()发生错误时返回-1。记住这些二进制数字?(无符号数)-1仅仅和IP地址255.255.255.255相符合!这可是广播地址!大错特 错!记住要先进行错误检查。

有没有其相反的方法呢? 它可以将一个in_addr结构体输出成点数格式?这样的话,你就要用到函数 inet_ntoa()("ntoa"的含义是"network to ascii"),就像这样:

printf("%s",inet_ntoa(ina.sin_addr));

它将输出IP地址。需要注意的是inet_ntoa()将结构体in-addr作为一个参数,不是长整形。同样需要注意的是它返回的是一个指向一个字符的 指针。它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用 inet_ntoa(),它就将覆盖上次调用时所得的IP地址。例如:

char *a1, *a2;

a1 = inet_ntoa(ina1.sin_addr); /* 这是198.92.129.1 */
a2 = inet_ntoa(ina2.sin_addr); /* 这是132.241.5.10 */
printf("address 1: %sn",a1);
printf("address 2: %sn",a2); 

输出如下:

address 1: 132.241.5.10

address 2: 132.241.5.10

假如你需要保存这个IP地址,使用strcopy()函数来指向你自己的字符指针。

socket()函数

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

domain 应该设置成 "AF_INET",就 象上面的数据结构struct sockaddr_in 中一样。

参数 type 告诉内核 是 SOCK_STREAM 类型还是 SOCK_DGRAM 类型。

把 protocol 设置为 "0"。

socket() 只是返回你以后在系统调用种可能用到的 socket 描述符,或 者在错误的时候返回-1。

bind()函数

<span style="font-size:14px;">#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen); </span>

sockfd 是调用 socket 返回的文件描述符。my_addr 是指向数据结构 struct sockaddr 的指针,它保存你的地址(即端口和 IP 地址) 信息。 addrlen 设置为 sizeof(struct sockaddr)。

<span style="font-size:14px;">#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MYPORT 3490
main()
   {
   int sockfd;
   struct sockaddr_in my_addr;
    sockfd = socket(AF_INET, SOCK_STREAM, 0); /*需要错误检查 */
    my_addr.sin_family = AF_INET; /* host byte order */
   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),; /* zero the rest of the struct */
    /* don't forget your error checking for bind(): */
   bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)); </span>

在处理自己的 IP 地址和/或端口的 时候,有些工作是可以自动处理的。

my_addr.sin_port = 0; /* 随机选择一个没有使用的端口 */

my_addr.sin_addr.s_addr = INADDR_ANY; /* 使用自己的IP地址 */

通过将0赋给 my_addr.sin_port,你告诉 bind() 自己选择合适的端 口。同样,将 my_addr.sin_addr.s_addr 设置为 INADDR_ANY,你告诉 它自动填上它所运行的机器的 IP 地址。 那么你可能注意到我没有将 INADDR_ANY 转 换为网络字节顺序!这是因为我知道内部的东西:INADDR_ANY 实际上就 是 0!即使你改变字节的顺序,0依然是0。但是完美主义者说应该处处一致,INADDR_ANY或许是12呢?你的代码就不能工作了,那么就看下面
的代码:

my_addr.sin_port = htons(0); /* 随机选择一个没有使用的端口 */

my_addr.sin_addr.s_addr = htonl(INADDR_ANY);/* 使用自己的IP地址 */

你或许不相信,上面的代码将可以随便移植。

在你调用 bind() 的时候,你要小心的另一件事情是:不要采用小于 1024的端口号。所有小于1024的端口号都被系统保留!你可以选择从1024 到65535的端口(如果它们没有被别的程序使用的话)。

你要注意的另外一件小事是:有时候你根本不需要调用它。如果使 用 connect() 来和远程机器进行通讯,你不需要关心你的本地端口号(就象你在使用 telnet 的时候),你只要简单的调用 connect() 就可以了,它会检查套接字是否绑定端口,如果没有,它会自己绑定一个没有使用的本地端 口。

connect()程序

<span style="font-size:14px;">#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); </span>

sockfd 是系统调用 socket() 返回的套接字文件描述符。serv_addr 是 保存着目的地端口和 IP 地址的数据结构 struct sockaddr。addrlen 设置 为 sizeof(struct sockaddr)。

<span style="font-size:14px;">#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#define DEST_IP "132.241.5.10"
  #define DEST_PORT 23
main()
   {
int sockfd;
struct sockaddr_in dest_addr; /* 目的地址*/
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 错误检查 */
dest_addr.sin_family = AF_INET; /* host byte order */
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),; /* zero the rest of the struct */
/* don't forget to error check the connect()! */
connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)); </span>

你应该检查 connect() 的返回值--它在错误的时候返回-1,并 设置全局错误变量 errno。

listen()函数

<span style="font-size:14px;">int listen(int sockfd, int backlog);</span>

sockfd 是调用 socket() 返回的套接字文件描述符。backlog 是在进入 队列中允许的连接数目。什么意思呢? 进入的连接是在队列中一直等待直到你接受 (accept() 请看下面的文章)连接。它们的数目限制于队列的允许。 大多数系统的允许数目是20,你也可以设置为5到10。

和别的函数一样,在发生错误的时候返回-1,并设置全局错误变量 errno。

accept()函数

想象发生 这样的事情:有人从很远的地方通过一个你在侦听 (listen()) 的端口连接 (connect()) 到你的机器。它的连接将加入到等待接受 (accept()) 的队列 中。你调用 accept() 告诉它你有空闲的连接。它将返回一个新的套接字文 件描述符!这样你就有两个套接字了,原来的一个还在侦听你的那个端口, 新的在准备发送 (send()) 和接收 ( recv()) 数据。这就是这个过程!

<span style="font-size:14px;">//函数是这样定义的:
#include <sys/socket.h>
int accept(int sockfd, void *addr, int *addrlen); </span>

sockfd 相当简单,是和 listen() 中一样的套接字描述符。addr 是个指 向局部的数据结构 sockaddr_in 的指针。这是要求接入的信息所要去的地 方(你可以测定那个地址在那个端口呼叫你)。在它的地址传递给 accept 之 前,addrlen 是个局部的整形变量,设置为 sizeof(struct sockaddr_in)。 accept 将不会将多余的字节给 addr。如果你放入的少些,那么它会通过改变
addrlen 的值反映出来。

<span style="font-size:14px;">#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MYPORT 3490 /*用户接入端口*/
#define BACKLOG 10 /* 多少等待连接控制*/
main()
   {
  int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */
  struct sockaddr_in my_addr; /* 地址信息 */
  struct sockaddr_in their_addr; /* connector's address information */
  int sin_size;
   sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 错误检查*/
   my_addr.sin_family = AF_INET; /* host byte order */
  my_addr.sin_port = htons(MYPORT); /* short, network byte order */
  my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
  bzero(&(my_addr.sin_zero),; /* zero the rest of the struct */
   /* don't forget your error checking for these calls: */
  bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
   listen(sockfd, BACKLOG);
   sin_size = sizeof(struct sockaddr_in);
  new_fd = accept(sockfd, &their_addr, &sin_size); </span>

在系统调用 send() 和 recv() 中你应该使用新的套接字描述符 new_fd。如果你只想让一个连接进来,那么你可以使用 close() 去关闭原 来的文件描述符 sockfd 来避免同一个端口更多的连接。

send() and recv()函数

send() 是这样的:

int send(int sockfd, const void *msg, int len, int flags);

sockfd 是你想发送数据的套接字描述符(或者是调用 socket() 或者是 accept() 返回的。)

msg 是指向你想发送的数据的指针。

len 是数据的长度。

把 flags 设置为 0 就可以了

这里是一些可能的例子:

char *msg = "Beej was here!";

  int len, bytes_sent;

  .

  .

  len = strlen(msg);

  bytes_sent = send(sockfd, msg, len, 0);

  .

  .

  .

send() 返回实际发送的数据的字节数--它可能小于你要求发送的数 目! 注意,有时候你告诉它要发送一堆数据可是它不能处理成功。它只是发送它可能发送的数据,然后希望你能够发送其它的数据。记住,如果 send() 返回的数据和 len 不匹配,你就应该发送其它的数据。但是这里也有个好消息:如果你要发送的包很小(小于大约 1K),它可能处理让数据一次发送完。最后要说得就是,它在错误的时候返回-1,并设置 errno。

recv() 函数很相似:

int recv(int sockfd, void *buf, int len, unsigned int flags);

sockfd 是要读的套接字描述符。buf 是要读的信息的缓冲。len 是缓冲的最大长度。flags 可以设置为0。(请参考recv() 的 man page。) recv() 返回实际读入缓冲的数据的字节数。或者在错误的时候返回-1, 同时设置 errno。

sendto() 和 recvfrom()函数

既然数据报套接字不是连接到远程主机的,那么在我们发送一个包之 前需要什么信息呢? 不错,是目标地址!看看下面的:

int sendto(int sockfd, const void *msg, int len, unsigned int flags,

   const struct sockaddr *to, int tolen);

你已经看到了,除了另外的两个信息外,其余的和函数 send() 是一样 的。 to 是个指向数据结构 struct sockaddr 的指针,它包含了目的地的 IP 地址和端口信息。tolen 可以简单地设置为 sizeof(struct sockaddr)。 和函数 send() 类似,sendto() 返回实际发送的字节数(它也可能小于 你想要发送的字节数!),或者在错误的时候返回 -1。

相似的还有函数 recv() 和 recvfrom()。recvfrom() 的定义是这样的:

int recvfrom(int sockfd, void *buf, int len, unsigned int flags,  struct sockaddr *from, int *fromlen);

又一次,除了两个增加的参数外,这个函数和 recv() 也是一样的。from 是一个指向局部数据结构 struct sockaddr 的指针,它的内容是源机器的 IP 地址和端口信息。fromlen 是个 int 型的局部指针,它的初始值为 sizeof(struct sockaddr)。函数调用返回后,fromlen 保存着实际储存在 from 中的地址的长度。

recvfrom() 返回收到的字节长度,或者在发生错误后返回 -1。

记住,如果你用 connect() 连接一个数据报套接字,你可以简单的调 用 send() 和 recv() 来满足你的要求。这个时候依然是数据报套接字,依 然使用 UDP,系统套接字接口会为你自动加上了目标和源的信息。

close()和shutdown()函数

你可以使用一般的 Unix 文件描述符 的 close() 函数:

  close(sockfd);

它将防止套接字上更多的数据的读写。任何在另一端读写套接字的企 图都将返回错误信息。

如果你想在如何关闭套接字上有多一点的控制,你可以使用函数 shutdown()。它允许你将一定方向上的通讯或者双向的通讯(就象close()一 样)关闭,你可以使用:

int shutdown(int sockfd, int how);

sockfd 是你想要关闭的套接字文件描述复。how 的值是下面的其中之 一:

  0 – 不允许接受

  1 – 不允许发送

  2 – 不允许发送和接受(和 close() 一样)

shutdown() 成功时返回 0,失败时返回 -1(同时设置 errno) 如果在无连接的数据报套接字中使用shutdown(),那么只不过是让 send() 和 recv() 不能使用(记住你在数据报套接字中使用了 connect 后 是可以使用它们的)。

getpeername()函数

函数 getpeername() 告诉你在连接的流式套接字上谁在另外一边。函 数是这样的:

#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);

sockfd 是连接的流式套接字的描述符。addr 是一个指向结构 struct sockaddr (或者是 struct sockaddr_in) 的指针,它保存着连接的另一边的 信息。addrlen 是一个 int 型的指针,它初始化为 sizeof(struct sockaddr)。函数在错误的时候返回 -1,设置相应的 errno。

一旦你获得它们的地址,你可以使用 inet_ntoa() 或者 gethostbyaddr() 来打印或者获得更多的信息。但是你不能得到它的帐号。

gethostname()函数

它返回你程 序所运行的机器的主机名字。然后你可以使用 gethostbyname() 以获得你 的机器的 IP 地址。

  下面是定义:

  #include <unistd.h>

int gethostname(char *hostname, size_t size);

参数很简单:hostname 是一个字符数组指针,它将在函数返回时保存

主机名。size是hostname 数组的字节长度。

函数调用成功时返回 0,失败时返回 -1,并设置 errno。

gethostbyname()&DNS

当一个人输入:

   $ telnet whitehouse.gov

telnet 能知道它将连接 (connect()) 到 "198.137.240.100"。

但是这是如何工作的呢? 你可以调用函数 gethostbyname():

<span style="font-size:14px;">#include <netdb.h>
  struct hostent *gethostbyname(const char *name); </span>

很明白的是,它返回一个指向 struct hostent 的指针。这个数据结构 是这样的:

<span style="font-size:14px;">struct hostent {
   char *h_name;
   char **h_aliases;
   int h_addrtype;
   int h_length;
   char **h_addr_list;
   };
   #define h_addr h_addr_list[0] </span>

struct hostent:

  h_name – 地址的正式名称。

  h_aliases – 空字节-地址的预备名称的指针。

  h_addrtype –地址类型; 通常是AF_INET。

  h_length – 地址的比特长度。

  h_addr_list – 零字节-主机网络地址指针。网络字节顺序。

  h_addr - h_addr_list中的第一地址。

gethostbyname() 成功时返回一个指向结构体 hostent 的指针,或者 是个空 (NULL) 指针。(但是和以前不同,不设置errno,h_errno 设置错 误信息。请看下面的 herror()。

<span style="font-size:14px;">    #include <stdio.h>
  #include <stdlib.h>
  #include <errno.h>
  #include <netdb.h>
  #include <sys/types.h>
  #include <netinet/in.h>
   int main(int argc, char *argv[])
   {
   struct hostent *h;
   if (argc != 2) { /* 检查命令行 */
   fprintf(stderr,"usage: getip addressn");
   exit(1);
   }
   if ((h=gethostbyname(argv[1])) == NULL) { /* 取得地址信息 */
   herror("gethostbyname");
   exit(1);
   }
   printf("Host name : %sn", h->h_name);
  printf("IP Address : %sn",inet_ntoa(*((struct in_addr *)h->h_addr)));
   return 0;
   } </span>

在使用 gethostbyname() 的时候,你不能用 perror() 打印错误信息 (因为 errno 没有使用),你应该调用 herror()。

相当简单,你只是传递一个保存机器名的字符串(例如 "whitehouse.gov") 给 gethostbyname(),然后从返回的数据结构 struct hostent 中获取信息。

唯一也许让人不解的是输出 IP 地址信息。h->h_addr 是一个 char *, 但是 inet_ntoa() 需要的是 struct in_addr。因此,我转换 h->h_addr 成 struct in_addr *,然后得到数据。

客户-服务器

客户--服务器之间可以使用SOCK_STREAM、SOCK_DGRAM 或者其它(只要它们采用相同的)。一些很好的客户--服务器的例子有 telnet/telnetd、 ftp/ftpd 和 bootp/bootpd。每次你使用 ftp 的时候,在远 端都有一个 ftpd 为你服务。

一般,在服务端只有一个服务器,它采用 fork() 来处理多个客户的连 接。基本的程序是:服务器等待一个连接,接受 (accept()) 连接,然后 fork() 一个子进程处理它。

简单的服务器

  这个服务器所做的全部工作是在流式连接上发送字符串 "Hello, World!n"。你要测试这个程序的话,可以在一台机器上运行该程序,然后 在另外一机器上登陆:

   $ telnet remotehostname 3490

remotehostname 是该程序运行的机器的名字。

服务器代码:

<span style="font-size:14px;">   #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 MYPORT 3490 /*定义用户连接端口*/
   #define BACKLOG 10 /*多少等待连接控制*/
   main()
 {
   int sockfd, new_fd; /* listen on sock_fd, new connection on new_fd */
   struct sockaddr_in my_addr; /* my address information */
   struct sockaddr_in their_addr; /* connector's address information */
   int sin_size;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
   perror("socket");
   exit(1);
   } 

    my_addr.sin_family = AF_INET; /* host byte order */
   my_addr.sin_port = htons(MYPORT); /* short, network byte order */
   my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
   bzero(&(my_addr.sin_zero),; /* zero the rest of the struct */ 

    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) { /* main accept() loop */
   sin_size = sizeof(struct sockaddr_in);
   if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
   &sin_size)) == -1) {
   perror("accept");
   continue;
   }
   printf("server: got connection from %sn",
   inet_ntoa(their_addr.sin_addr));
   if (!fork()) { /* this is the child process */
   if (send(new_fd, "Hello, world!n", 14, 0) == -1)
   perror("send");
   close(new_fd);
   exit(0);
   }
   close(new_fd); /* parent doesn't need this */
     while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
   }
 } </span>

客户代码:

<span style="font-size:14px;">#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 PORT 3490 /* 客户机连接远程主机的端口 */
   #define MAXDATASIZE 100 /* 每次可以接收的最大字节 */
   int main(int argc, char *argv[])
  {
   int sockfd, numbytes;
   char buf[MAXDATASIZE];
   struct hostent *he;
   struct sockaddr_in their_addr; /* connector's address information */
    if (argc != 2) {
   fprintf(stderr,"usage: client hostnamen");
   exit(1);
   }
    if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
   herror("gethostbyname");
   exit(1);
   } 

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
   perror("socket");
   exit(1);
   } 

   their_addr.sin_family = AF_INET; /* host byte order */
  their_addr.sin_port = htons(PORT); /* short, network byte order */
  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
  bzero(&(their_addr.sin_zero),; /* zero the rest of the struct */
   if (connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1) {
   perror("connect");
   exit(1);
   }
   if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1) {
   perror("recv");
   exit(1);
   }
   buf[numbytes] = '';
   printf("Received: %s",buf);
   close(sockfd);
   return 0;
   } </span>

数据包 Sockets : talker.c 和 listener.c

listener.c:

<span style="font-size:14px;">       #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 MYPORT 4950 /* the port users will be sending to */
       #define MAXBUFLEN 100
       main()
  {
   int sockfd;
   struct sockaddr_in my_addr; /* my address information */
   struct sockaddr_in their_addr; /* connector's address information */
   int addr_len, numbytes;
   char buf[MAXBUFLEN];
         if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
   perror("socket");
   exit(1);
   }
         my_addr.sin_family = AF_INET; /* host byte order */
   my_addr.sin_port = htons(MYPORT); /* short, network byte order */
   my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
   bzero(&(my_addr.sin_zero),; /* zero the rest of the struct */
         if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1) {
   perror("bind");
   exit(1);
   }
         addr_len = sizeof(struct sockaddr);
   if ((numbytes=recvfrom(sockfd, buf, MAXBUFLEN, 0,
   (struct sockaddr *)&their_addr, &addr_len)) == -1) {
   perror("recvfrom");
   exit(1);
   }
         printf("got packet from %sn",inet_ntoa(their_addr.sin_addr));
   printf("packet is %d bytes longn",numbytes);
   buf[numbytes] = '';
   printf("packet contains "%s"n",buf);
         close(sockfd);
   } </span>

注意在我们的调用 socket(),我们最后使用了 SOCK_DGRAM。同时, 没有必要去使用 listen() 或者 accept()。我们在使用无连接的数据报套接字!

talker.c:

<span style="font-size:14px;">#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 MYPORT 4950 /* the port users will be sending to */
    int main(int argc, char *argv[])
   {
   int sockfd;
   struct sockaddr_in their_addr; /* connector's address information */
   struct hostent *he;
   int numbytes; 

    if (argc != 3) {
   fprintf(stderr,"usage: talker hostname messagen");
   exit(1);
   } 

    if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
   herror("gethostbyname");
   exit(1);
   } 

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
   perror("socket");
   exit(1);
   } 

    their_addr.sin_family = AF_INET; /* host byte order */
   their_addr.sin_port = htons(MYPORT); /* short, network byte order
*/
   their_addr.sin_addr = *((struct in_addr *)he->h_addr);
   bzero(&(their_addr.sin_zero),; /* zero the rest of the struct */
    if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0,
   (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1) {
   perror("sendto");
   exit(1);
   }
    printf("sent %d bytes to %sn",numbytes,inet_ntoa(their_addr.sin_addr));
    close(sockfd);
    return 0;
   } </span>
时间: 2024-07-30 20:31:43

socket网络编程的相关内容的相关文章

Linux Socket 网络编程

Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后,过段时间不看,重新拾起这些知识的时候又要从头开始,所以,在这里做个笔记也算是做个模板,以后可以直接从某一个阶段开始接着玩... 1. socket套接字介绍 socket机制其实就是包括socket, bind, listen, connect, accept等函数的方法,其通过指定的函数实现不同

Socket网络编程初探

MarkdownPad Document Socket网络编程初探 客户端/服务器架构 即C/S架构,其实web服务在某种意义上也算是C/S架构 一个特点是服务器端持续运行对外提供服务 为何学习socket一定要先学习互联网协议: C/S架构的软件是基于网络进行通信的 网络的核心就是一堆协议,即标准,想要开发一款基于网络通信的软件就必须遵循这些标准 socket是处在应用层和传输层中间的一组接口 说到这,那么socket到底是个什么呢?Socket是应用层与TCP/IP协议族通信的中间软件抽象层

Python之路【第九篇】:Python基础(25)——socket网络编程

socket网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用打开.读写.关闭模式来操作.socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO.打开.关闭) socket和file的区别: file模块是针对某个指定

Linux程序设计学习笔记----Socket网络编程基础之TCP/IP协议簇

转载请注明出处: ,谢谢! 内容提要 本节主要学习网络通信基础,主要涉及的内容是: TCP/IP协议簇基础:两个模型 IPv4协议基础:IP地址分类与表示,子网掩码等 IP地址转换:点分十进制\二进制 TCP/IP协议簇基础 OSI模型 我们知道计算机网络之中,有各种各样的设备,那么如何实现这些设备的通信呢? 显然是通过标准的通讯协议,但是,整个网络连接的过程相当复杂,包括硬件.软件数据封包与应用程序的互相链接等等,如果想要写一支将联网全部功能都串连在一块的程序,那么当某个小环节出现问题时,整只

Python面向对象进阶和socket网络编程-day08

写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __init__(self,name): self.name=name p = Chinese('standby') # 实例化一个对象 print(p) # 打印这个对象 --- <__main__.Chinese object at 0x0000000000B3A978> - 示例2: >&g

C# Socket网络编程实例

本文实例讲述了C# Socket网络编程技巧.分享给大家供大家参考.具体分析如下: 客户端要连接服务器:首先要知道服务器的IP地址.而服务器里有很多的应用程序,每一个应用程序对应一个端口号 所以客户端想要与服务器中的某个应用程序进行通信就必须要知道那个应用程序的所在服务器的IP地址,及应用程序所对应的端口号 TCP协议: 安全稳定,一般不会发生数据丢失,但是效率低.利用TCP发生数据一般经过3次握手(所有效率低,自己百度三次握手) UDP协议: 快速,效率高,但是不稳定,容易发生数据丢失(没有经

Socket网络编程--网络爬虫(1)

我们这个系列准备讲一下--网络爬虫.网络爬虫是搜索引擎系统中十分重要的组成部分,它负责从互联网中搜集网页,采集信息,这些网页信息用于建立索引从而为搜索引擎提供支持,它决定着整个引擎系统的内容是否丰富,信息是否即时,因此其性能的优劣直接影响着搜索引擎的效果.网络爬虫的基本工作原理: (1)从一个初始URL集合中挑选一个URL,下载该URL对应的页面: (2)解析该页面,从该页面中抽取出其包含的URL集合,接下来将抽取的URL集合再添加到初始URL集合中: (3)重复前两个过程,直到爬虫达到某种停止

windows下的socket网络编程(入门级)

windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先写了个简单的winSocket网路通信的例子,以便以后用到的时候有个参考. windows下使用winsock编程与linux/unix的区别在于windows下需要先有一个初始化的操作,结束的时候需要一个清理的操作.还有windows下编译的时候需要连接ws32_lib库. 大致过程如下 1.初始

linux下C语言socket网络编程简例

转自:http://blog.csdn.net/kikilizhm/article/details/7858405 这里给出在linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端:客户端在接受到数据后打印出来,然后关闭.程序里有详细的说明,其中对具体的结构体和函数的实现可以参考其他资料. 程序说明: 这里服务器的端口号和ip地址使用固定的设置,移植时可以根据具体情况更改,可以改写为参数传递更好,这里为了方便,使用固定的. 移