通過網卡,讓我們能達到通信,對unix是相當的複雜,組要是socket每一層都是用了不同的通信協議,需要好多設置好多的選項。因此在/dev目錄下,並沒有網卡對應的文件。
socket不僅可以用於各種傳輸協議的IP的連接。也可以用於內核支持的所有其他地址和協議類型。
套接字是使用socket庫函數生成的。然後bind函數等。
socket主要用於協議的選擇,通信類型,地址族。
bind函數主要目的是給到戒子分配本地地址。該函數的傳遞一個sockaddr_type 的參數,定義了本地地址。因爲不同地址組的地址類型是不同的。type制定了所需的地址類型。
這個時候,我們來點代碼
#ifndef _LINUX_IN_H
#define _LINUX_IN_H
#include <linux/types.h>
#include <linux/socket.h>
/* Standard well-defined IP protocols. */
enum {
IPPROTO_IP = 0, /* Dummy protocol for TCP */
IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
IPPROTO_TCP = 6, /* Transmission Control Protocol */
IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
IPPROTO_PUP = 12, /* PUP protocol */
IPPROTO_UDP = 17, /* User Datagram Protocol */
IPPROTO_IDP = 22, /* XNS IDP protocol */
IPPROTO_RSVP = 46, /* RSVP protocol */
IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
IPPROTO_AH = 51, /* Authentication Header protocol */
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
IPPROTO_COMP = 108, /* Compression Header protocol */
IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
IPPROTO_RAW = 255, /* Raw IP packets */
IPPROTO_MAX
};
/* Internet address. */
struct in_addr {
__u32 s_addr;
};
#define IP_TOS 1
#define IP_TTL 2
#define IP_HDRINCL 3
#define IP_OPTIONS 4
#define IP_ROUTER_ALERT 5
#define IP_RECVOPTS 6
#define IP_RETOPTS 7
#define IP_PKTINFO 8
#define IP_PKTOPTIONS 9
#define IP_MTU_DISCOVER 10
#define IP_RECVERR 11
#define IP_RECVTTL 12
#define IP_RECVTOS 13
#define IP_MTU 14
#define IP_FREEBIND 15
#define IP_IPSEC_POLICY 16
#define IP_XFRM_POLICY 17
/* BSD compatibility */
#define IP_RECVRETOPTS IP_RETOPTS
/* IP_MTU_DISCOVER values */
#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
#define IP_PMTUDISC_WANT 1 /* Use per route hints */
#define IP_PMTUDISC_DO 2 /* Always DF */
#define IP_MULTICAST_IF 32
#define IP_MULTICAST_TTL 33
#define IP_MULTICAST_LOOP 34
#define IP_ADD_MEMBERSHIP 35
#define IP_DROP_MEMBERSHIP 36
#define IP_UNBLOCK_SOURCE 37
#define IP_BLOCK_SOURCE 38
#define IP_ADD_SOURCE_MEMBERSHIP 39
#define IP_DROP_SOURCE_MEMBERSHIP 40
#define IP_MSFILTER 41
#define MCAST_JOIN_GROUP 42
#define MCAST_BLOCK_SOURCE 43
#define MCAST_UNBLOCK_SOURCE 44
#define MCAST_LEAVE_GROUP 45
#define MCAST_JOIN_SOURCE_GROUP 46
#define MCAST_LEAVE_SOURCE_GROUP 47
#define MCAST_MSFILTER 48
#define MCAST_EXCLUDE 0
#define MCAST_INCLUDE 1
/* These need to appear somewhere around here */
#define IP_DEFAULT_MULTICAST_TTL 1
#define IP_DEFAULT_MULTICAST_LOOP 1
/* Request struct for multicast socket ops */
struct ip_mreq
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
struct ip_mreqn
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_address; /* local IP address of interface */
int imr_ifindex; /* Interface index */
};
struct ip_mreq_source {
__u32 imr_multiaddr;
__u32 imr_interface;
__u32 imr_sourceaddr;
};
struct ip_msfilter {
__u32 imsf_multiaddr;
__u32 imsf_interface;
__u32 imsf_fmode;
__u32 imsf_numsrc;
__u32 imsf_slist[1];
};
#define IP_MSFILTER_SIZE(numsrc) \
(sizeof(struct ip_msfilter) - sizeof(__u32) \
+ (numsrc) * sizeof(__u32))
struct group_req
{
__u32 gr_interface; /* interface index */
struct __kernel_sockaddr_storage gr_group; /* group address */
};
struct group_source_req
{
__u32 gsr_interface; /* interface index */
struct __kernel_sockaddr_storage gsr_group; /* group address */
struct __kernel_sockaddr_storage gsr_source; /* source address */
};
struct group_filter
{
__u32 gf_interface; /* interface index */
struct __kernel_sockaddr_storage gf_group; /* multicast address */
__u32 gf_fmode; /* filter mode */
__u32 gf_numsrc; /* number of sources */
struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
};
#define GROUP_FILTER_SIZE(numsrc) \
(sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \
+ (numsrc) * sizeof(struct __kernel_sockaddr_storage))
struct in_pktinfo
{
int ipi_ifindex;
struct in_addr ipi_spec_dst;
struct in_addr ipi_addr;
};
/* Structure describing an Internet (IP) socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {
sa_family_t sin_family; /* Address family */
unsigned short int sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
重點看紅色部分,
sin_family;地址族 unsigned short int sin_port; 端口號
struct in_addr sin_addr; 網絡地址。
在這裏考慮到網絡字節序還有大端小端的問題。
下面有個簡單的例子。
使用了基本的用戶函數 socket,bind,listion select 函數
<strong><span style="font-size: 18px;">首先 運行在linux 運行gcc -g -o select select.c</span></strong><pre class="cpp" name="code">/ *******select.c*********/
/ *******Using select() for I/O multiplexing */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* port we're listening on */
#define PORT 2020
int main(int argc, char *argv[])
{
/*定義描述符集合 */
fd_set master;
/* 定義select函數可讀的描述符*/
fd_set read_fds;
/* 服務器地址 */
struct sockaddr_in serveraddr;
/* 客戶地址 */
struct sockaddr_in clientaddr;
/* 定義最大描述符數 */
int fdmax;
/* 監聽描述符 */
int listener;
/* accept描述符 */
int newfd;
/* 緩衝 */
char buf[1024];
int nbytes;
/* 設置 setsockopt() SO_REUSEADDR */
int yes = 1;
int addrlen;
int i, j;
/* 清除 */
FD_ZERO(&master);
FD_ZERO(&read_fds);
/* 連接 */
if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Server-socket() error lol!");
exit(1);
}
printf("Server-socket() is OK...\n");
/*判斷地址以用 */
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");
/* bind */
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
if(bind(listener, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("Server-bind() error lol!");
exit(1);
}
printf("Server-bind() is OK...\n");
/* listen */
if(listen(listener, 10) == -1)
{
perror("Server-listen() error lol!");
exit(1);
}
printf("Server-listen() is OK...\n");
/* 把 listener 加到 master set */
FD_SET(listener, &master);
/* keep track of the biggest file descriptor */
fdmax = listener; /* so far, it's this one*/
/* 循環了 */
for(;;)
{
/* copy it */
read_fds = master;
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("Server-select() error lol!");
exit(1);
}
printf("Server-select() is OK...\n");
/*從存在的描述符中查找要讀的數據*/
for(i = 0; i <= fdmax; i++)
{
if(FD_ISSET(i, &read_fds))
{ /* 得到一個... */
if(i == listener)
{
/* h處理這個的連接 */
addrlen = sizeof(clientaddr);
if((newfd = accept(listener, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
{
perror("Server-accept() error lol!");
}
else
{
printf("Server-accept() is OK...\n");
FD_SET(newfd, &master); /* add to master set */
if(newfd > fdmax)
{ /* keep track of the maximum */
fdmax = newfd;
}
printf("%s: New connection from %s on socket %d\n", argv[0], inet_ntoa(clientaddr.sin_addr), newfd);
}
}
else
{
/* 處理從客戶端來的數據*/
if((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0)
{
/* 沒有數據 */
if(nbytes == 0)
/* 斷開連接。 */
printf("%s: socket %d hung up\n", argv[0], i);
else
perror("recv() error lol!");
/* 關閉... */
close(i);
/* 刪除這個連接符 */
FD_CLR(i, &master);
}
else
{
/* we got some data from a client*/
for(j = 0; j <= fdmax; j++)
{
/* 發給每個人! */
if(FD_ISSET(j, &master))
{
/* 除了監聽的和自己的。 */
if(j != listener && j != i)
{
if(send(j, buf, nbytes, 0) == -1)
perror("send() error lol!");
}
}
}
}
}
}
}
}
return 0;
}</pre><br>
<pre></pre>
<pre class="cpp" name="code"><strong><span style="font-size: 18px;">然後在運行 ./select & 或者ctrl+z 讓他後臺運行</span></strong></pre><pre class="cpp" name="code"><span style="font-size: 18px;"><strong>開一個窗口 運行telnet localhostip 2020</strong> </span></pre><pre class="cpp" name="code"><span style="font-size: 18px;">程序如下</span></pre><pre class="cpp" name="code"></pre>
<p>更多文章,歡迎訪問<a href="http://blog.csdn.net/wallwind">http://blog.csdn.net/wallwind</a> 轉載請註明出處</p>