关于Linux网路编程的介绍,网上很多资料,这里就不赘言(详细内容可见参考资料),本文主要对创建一个简单的服务器与客户端程序进行总结。
1 Server
1.1 流程
关于创建一个网络服务器程序的流程,参考资料[2]有总结,这里将其再现如下:
socket()-->bind()-->listen()-->accept()->write()/read()
1.2 实例
参考资料[2]已经给出了一个比较简单而完整的服务端案例,这里将其再现如下:
/******* 服务器程序 (server.c) ************/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size, portnumber;
char hello[] = "Hello! Are You Fine?\n";
if( argc != 2 ) {
fprintf(stderr,"Usage:%s portnumber\a\n", argv[0]);
exit(1);
}
if( ( portnumber = atoi( argv [1] )) < 0 ){
fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]);
exit(1);
}
/* 服务器端开始建立socket描述符 */
if( ( sockfd = socket( AF_INET, SOCK_STREAM, 0) ) == -1 ) {
fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
exit(1);
}
/* 服务器端填充sockaddr结构 */
bzero( &server_addr, sizeof(struct sockaddr_in) );
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl( INADDR_ANY );
server_addr.sin_port = htons( portnumber );
/* 捆绑sockfd描述符 */
if( bind( sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr))==-1) {
fprintf( stderr, "Bind error:%s\n\a", strerror( errno ) );
exit(1);
}
/* 监听sockfd描述符 */
if( listen(sockfd,5) == -1) {
fprintf( stderr, "Listen error:%s\n\a", strerror( errno ) );
exit(1);
}
while(1)
{
/* 服务器阻塞,直到客户程序建立连接 */
sin_size = sizeof(struct sockaddr_in);
if( ( new_fd = accept( sockfd, (struct sockaddr *)(&client_addr), &sin_size )) == -1) {
fprintf(stderr,"Accept error:%s\n\a", strerror( errno ) );
exit( 1 );
}
printf("Server get connection from %s\n",
inet_ntoa( client_addr.sin_addr ) );
if( write( new_fd, hello, strlen( hello ) ) == -1 ) {
fprintf( stderr, "Write Error:%s\n", strerror( errno ) );
exit(1);
}
/* 这个通讯已经结束 */
close( new_fd );
/* 循环下一个 */
}
close( sockfd );
exit(0);
}
2 Client
2.1 流程
根据参考资料[2]的说明,相对于服务器程序而言,创建一个客户端程序的流程比较简单,只需要两步即可:
socket()-->connect()-->read()/write()
2.2 实例
参考资料[2]已经给出了一个比较简单但是完整的客户端程序,这里将其再现如下:
/******* 客户端程序 client.c ************/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int sockfd;
char buffer[1024];
struct sockaddr_in server_addr;
struct hostent *host;
int portnumber, nbytes;
if( argc != 3) {
fprintf( stderr, "Usage:%s hostname portnumber\a\n", argv[0] );
exit(1);
}
if( ( host = gethostbyname( argv[1] ) ) == NULL) {
fprintf(stderr,"Gethostname error\n");
exit(1);
}
if( ( portnumber = atoi( argv[2] ) )<0) {
fprintf( stderr, "Usage:%s hostname portnumber\a\n", argv[0] );
exit(1);
}
/* 客户程序开始建立 sockfd描述符 */
if( ( sockfd = socket( AF_INET,SOCK_STREAM, 0 ) ) == -1) {
fprintf( stderr, "Socket Error:%s\a\n", strerror(errno) );
exit(1);
}
/* 客户程序填充服务端的资料 */
bzero( &server_addr, sizeof( server_addr ) );
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( portnumber );
server_addr.sin_addr = *( ( struct in_addr * )host->h_addr );
/* 客户程序发起连接请求 */
if( connect( sockfd, ( struct sockaddr * )( &server_addr ), sizeof( struct sockaddr ) ) ==-1 ) {
fprintf(stderr, "Connect Error:%s\a\n", strerror(errno));
exit(1);
}
/* 连接成功了 */
if( ( nbytes = read(sockfd, buffer, 1024 ) ) == -1 ) {
fprintf(stderr, "Read Error:%s\n", strerror( errno ));
exit(1);
}
buffer[nbytes] = '\0';
printf("I have received:%s\n", buffer);
/* 结束通讯 */
close( sockfd );
exit(0);
}
参考资料
[2]Linux网络编程入门
[3]Linux_套接字编程
[4]linux套接字编程
[6]套接字传输文件的试验