1 /*socket->bind->listen->accept->recv/recvfrom->send/sendto->close 2 3 客户端:socket->connect->send/sendto->recv/recvfrom->close 4 5 其中服务器端首先建立起socket,然后调用本地端口的绑定,接着就开始与客服端建立联系,并接收客户端发送的消息。 6 客户端则在建立socket之后调用connect函数来建立连接。 7 8 服务器端的源代码如下所示:*/ 9 10 /*"server.c"*/ 11 12 #include<sys/types.h> 13 #include<sys/socket.h> 14 #include<stdio.h> 15 #include<stdlib.h> 16 #include<errno.h> 17 #include<string.h> 18 #include<unistd.h> 19 #include<netinet/in.h> 20 21 #define PORT 3490 //端口 22 23 #define BUFFER_SIZE 1024 //缓冲区大小 24 25 #define MAX_QUE_CONN_NM 5 //服务器等待连接队列的最大长度。 26 27 int main(){ 28 29 struct sockaddr_in server_sockaddr,client_sockaddr; //分别定义服务器和客户端套接字 30 int sin_size,recvbytes; 31 int server_fd,client_fd; 32 char buf[BUFFER_SIZE]; //缓冲区 33 34 /* 35 SOCKET PASCAL FAR socket( int af, int type, int protocol); 36 af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。 37 type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。 38 常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。 39 protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。 40 常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等, 41 它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。 42 */ 43 if((server_fd = socket(AF_INET,SOCK_STREAM,0))== -1){ //建立socket连接www.linuxidc.com 44 perror("create socket fail"); 45 exit(1); 46 } 47 48 printf("Socket id=%d\n",server_fd); 49 50 /*设置sockaddr_in结构体中的相关参数*/ 51 52 server_sockaddr.sin_family = AF_INET; 53 server_sockaddr.sin_port = htons(PORT); //由于在写网络程序时字节的网络顺序和主机顺序会有问题 54 server_sockaddr.sin_addr.s_addr = INADDR_ANY; //即0.0.0.0 任意地址 55 bzero(&(server_sockaddr.sin_zero),8); 56 int i = 1; //允许重复使用本地地址与套接字进行绑定 57 58 /*int PASCAL FAR setsockopt(SOCKET s,int level,int optname,const char FAR *optval,int optlen); 59 s:标识一个套接字的描述符。 60 level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。 61 optname:需设置的选项。 62 optval:指针,指向存放选项值的缓冲区。 63 optlen:optval缓冲区长度。 64 */ 65 setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i)); 66 67 /* 68 int bind(SOCKET socket, const struct sockaddr *address, 69 socklen_t address_len); 70 参数说明: 71 socket:是一个套接字。 72 address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。 73 address_len:确定address缓冲区的长度。 74 返回值:如果函数执行成功,返回值为0,否则为SOCKET_ERROR。 75 */ 76 if(bind(server_fd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1){ //绑定函数bind 77 perror("bind fail"); 78 exit(1); 79 } 80 81 printf("Bind success!\n"); 82 83 /* 84 int PASCAL FAR listen( SOCKET s, int backlog); 85 S:用于标识一个已捆绑未连接套接口的描述字。 86 backlog:等待连接队列的最大长度。 87 */ 88 if(listen(server_fd,MAX_QUE_CONN_NM)== -1){ //调用listen函数,创建为处理请求的队列 89 perror("listen fail"); 90 exit(1); 91 } 92 93 printf("Listening......\n"); 94 95 /* 96 SOCKET PASCAL FAR accept( SOCKET s, struct sockaddr FAR* addr,int FAR* addrlen); 97 s:套接口描述字,该套接口在listen()后监听连接。 98 addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。 99 addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。 100 */ 101 if((client_fd = accept(server_fd,(struct sockaddr *)&client_sockaddr,&sin_size))==-1){//调用accept函数,等待客户端的接 102 perror("accept fail"); 103 exit(1); 104 } 105 106 printf("server: got connection from %s \n",inet_ntoa(client_sockaddr.sin_addr)); 107 108 memset(buf,0,sizeof(buf)); 109 /* 110 int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags); 111 s:一个标识已连接套接口的描述字。 112 buf:用于接收数据的缓冲区。 113 len:缓冲区长度。 114 flags:指定调用方式。通常写成0 115 */ 116 if((recvbytes = recv(client_fd,buf,BUFFER_SIZE,0)) == -1){//调用recv函数接收客户端的请求 117 perror("recv fail"); 118 exit(1); 119 } 120 121 printf("Received a message: %s\n",buf); 122 123 124 /*向客户起写数据*/ 125 if(write(client_fd,"客户端我收到你发来的数据了,你能收到这句应答吗?\n",1024)==-1) 126 perror("write error!"); 127 128 close(client_fd); 129 130 close(server_fd); 131 exit(0); 132 } 133 134 135 136 137 138 /*客户端*/ 139 /*client.c 运行方式:./client localhost*/ 140 #include <stdio.h> 141 #include <stdlib.h> 142 #include <errno.h> 143 #include <string.h> 144 #include <netdb.h> 145 #include <sys/types.h> 146 #include <netinet/in.h> 147 #include <sys/socket.h> 148 #define PORT 3490 149 #define MAXDATASIZE 5000 150 int main(int argc,char **argv) 151 { 152 int sockfd,nbytes; 153 char buf[1024]; 154 struct hostent *he; 155 struct sockaddr_in srvaddr; 156 if(argc!=2) 157 { 158 perror("Usage:client hostname\n"); 159 exit(1); 160 } 161 /*函数gethostbyname获得指定域名地址所对应的ip地址*/ 162 if((he=gethostbyname(argv[1]))==NULL) 163 { 164 perror("gethostbyname"); 165 exit(1); 166 } 167 /*创建套接字,返回套接字描述符*/ 168 if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) 169 { 170 perror("create socket error"); 171 exit(1); 172 } 173 bzero(&srvaddr,sizeof(srvaddr)); 174 /*用获得的远程服务器进程的ip地址和端口号来填充一个internet套接字地址结构*/ 175 srvaddr.sin_family=AF_INET; 176 srvaddr.sin_port=htons(PORT); 177 srvaddr.sin_addr=*((struct in_addr *)he->h_addr); 178 /*用connect于这个远程服务器建立一个internet连接*/ 179 if(connect(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1) 180 { 181 perror("connect error"); 182 exit(1); 183 } 184 185 186 if((send(sockfd,"客户端向服务端发送数据,服务端你收到了吗?",1024,0)) == -1) 187 { 188 perror("send error"); 189 exit(1); 190 } 191 192 193 194 /*调用read函数读取服务器write过来的信息*/ 195 if((nbytes=read(sockfd,buf,MAXDATASIZE))==-1) 196 { 197 perror("read error"); 198 exit(1); 199 } 200 buf[nbytes]='\0'; 201 printf("read: %s",buf); 202 close(sockfd); 203 }
运行方式: gcc -o service service.c
gcc -o client client.c
chmod +x service
chmod +x client
在一个终端运行:./service
在另一个终端运行:./client localhost
服务端输出:
Socket id=3 Bind success! Listening...... server: got connection from 127.0.0.1 Received a message: 客户端向服务端发送数据,服务端你收到了吗?
客户端输出:
read: 客户端我收到你发来的数据了,你能收到这句应答吗?